em-midori 0.0.5 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.resources/slogan.png +0 -0
- data/.travis.yml +4 -4
- data/lib/em-midori.rb +6 -2
- data/lib/em-midori/api.rb +33 -28
- data/lib/em-midori/clean_room.rb +3 -2
- data/lib/em-midori/const.rb +48 -0
- data/lib/em-midori/debug.rb +29 -0
- data/lib/em-midori/define_class.rb +7 -0
- data/lib/em-midori/em_midori.rb +5 -6
- data/lib/em-midori/error.rb +7 -0
- data/lib/em-midori/request.rb +61 -0
- data/lib/em-midori/response.rb +10 -47
- data/lib/em-midori/route.rb +8 -0
- data/lib/em-midori/server.rb +71 -8
- data/lib/em-midori/version.rb +1 -1
- data/lib/em-midori/websocket.rb +63 -0
- metadata +23 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 49747119b2524c9b0f81ca22a1c9f27010b880de
|
4
|
+
data.tar.gz: d32a3a67fd807cdeb7c49d5b7a90aacd24f24f43
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 51732ede10120a05f89e960826aadffb5342efec233eaaff238a9b82c887c905e09cae0357b8c6802f05db0f77e011c709cd0fa2b3bcce366e8aee92297a524e
|
7
|
+
data.tar.gz: c7e2497cdeed26883d3a5dff6d1195a77c27926ad46e01fd3a0bb556abcdd8bb0f5fd14a7191cbb7c7f881450c23894ff7f5e389db6551a7751fecbfc0976ce3
|
data/.gitignore
CHANGED
Binary file
|
data/.travis.yml
CHANGED
@@ -9,16 +9,16 @@ rvm:
|
|
9
9
|
|
10
10
|
jdk:
|
11
11
|
- openjdk7
|
12
|
-
-
|
12
|
+
- oraclejdk8
|
13
13
|
|
14
14
|
matrix:
|
15
15
|
exclude:
|
16
16
|
- rvm: 2.2.5
|
17
|
-
jdk:
|
17
|
+
jdk: openjdk7
|
18
18
|
- rvm: 2.3.1
|
19
|
-
jdk:
|
19
|
+
jdk: openjdk7
|
20
20
|
- rvm: rbx-3.20
|
21
|
-
jdk:
|
21
|
+
jdk: openjdk7
|
22
22
|
allow_failures:
|
23
23
|
- rvm: jruby-head
|
24
24
|
- rvm: rbx-3.20
|
data/lib/em-midori.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
|
+
require 'digest/sha1'
|
1
2
|
require 'em-midori/version'
|
3
|
+
require 'em-midori/debug'
|
4
|
+
require 'em-midori/const'
|
2
5
|
require 'em-midori/define_class'
|
6
|
+
require 'em-midori/error'
|
3
7
|
require 'em-midori/clean_room'
|
4
8
|
require 'em-midori/em_midori'
|
5
9
|
require 'em-midori/request'
|
6
10
|
require 'em-midori/response'
|
7
11
|
require 'em-midori/api'
|
12
|
+
require 'em-midori/route'
|
8
13
|
require 'em-midori/server'
|
9
|
-
|
10
|
-
# Midori.run(Midori::API, '0.0.0.0', 8080)
|
14
|
+
require 'em-midori/websocket'
|
data/lib/em-midori/api.rb
CHANGED
@@ -155,6 +155,13 @@ class Midori::API
|
|
155
155
|
# end
|
156
156
|
def eventsource(path, &block) end
|
157
157
|
|
158
|
+
# 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
|
158
165
|
def add_route(method, path, block)
|
159
166
|
@route = Array.new if @route.nil?
|
160
167
|
if path.class == String
|
@@ -165,24 +172,33 @@ class Midori::API
|
|
165
172
|
nil
|
166
173
|
end
|
167
174
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
175
|
+
# Process after receive data from client
|
176
|
+
# === Attributes
|
177
|
+
# * +request+ [+StringIO+] - Http Raw Request
|
178
|
+
# === Returns
|
179
|
+
# [+Midori::Response+] - Http response
|
180
|
+
def receive(request, connection=nil)
|
181
|
+
@route.each do |route|
|
182
|
+
matched = match(route.method, route.path, request.method, request.path)
|
183
|
+
if matched
|
184
|
+
clean_room = CleanRoom.new(request)
|
185
|
+
if request.websocket?
|
186
|
+
# Send 101 Switching Protocol
|
187
|
+
connection.send_data Midori::Response.new(101, {
|
188
|
+
'Upgrade' => 'websocket',
|
189
|
+
'Connection' => 'Upgrade',
|
190
|
+
'Sec-WebSocket-Accept' => Digest::SHA1.base64digest(request.header['Sec-WebSocket-Key'] +'258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
|
191
|
+
}, '')
|
192
|
+
result = lambda {clean_room.instance_exec(connection.websocket, *matched, &route.function)}.call
|
193
|
+
return Midori::Response.new
|
194
|
+
else
|
195
|
+
result = lambda {clean_room.instance_exec(*matched, &route.function)}.call
|
196
|
+
end
|
176
197
|
clean_room.body = result if result.class == String
|
177
198
|
return clean_room.response
|
178
|
-
rescue => e
|
179
|
-
puts e
|
180
|
-
return Midori::Response.new(500, {}, 'Internal Server Error')
|
181
199
|
end
|
182
200
|
end
|
183
|
-
|
184
|
-
# 404
|
185
|
-
Midori::Response.new(404, {}, '404 Not Found')
|
201
|
+
raise Midori::Error::NotFound
|
186
202
|
end
|
187
203
|
|
188
204
|
# Match route with given definition
|
@@ -196,10 +212,9 @@ class Midori::API
|
|
196
212
|
# else returns an array of parameter string matched
|
197
213
|
# === Examples
|
198
214
|
# match('GET', /^\/user\/(.*?)\/order\/(.*?)$/, '/user/foo/order/bar') # => ['foo', 'bar']
|
199
|
-
def match(method, path,
|
200
|
-
|
201
|
-
|
202
|
-
result = request[1].match(path)
|
215
|
+
def match(method, path, request_method, request_path)
|
216
|
+
if request_method == method
|
217
|
+
result = request_path.match(path)
|
203
218
|
return result.to_a[1..-1] if result
|
204
219
|
false
|
205
220
|
else
|
@@ -233,14 +248,4 @@ class Midori::API
|
|
233
248
|
add_route(method.upcase, args[0], block) #args[0]: path
|
234
249
|
end
|
235
250
|
end
|
236
|
-
|
237
251
|
end
|
238
|
-
|
239
|
-
class Midori::Route
|
240
|
-
attr_accessor :method, :path, :function
|
241
|
-
def initialize(method, path, function)
|
242
|
-
@method = method
|
243
|
-
@path = path
|
244
|
-
@function = function
|
245
|
-
end
|
246
|
-
end
|
data/lib/em-midori/clean_room.rb
CHANGED
@@ -0,0 +1,48 @@
|
|
1
|
+
module Midori::Const
|
2
|
+
STATUS_CODE = {
|
3
|
+
100 => '100 Continue',
|
4
|
+
101 => '101 Switching Protocols',
|
5
|
+
200 => '200 OK',
|
6
|
+
201 => '201 Created',
|
7
|
+
202 => '202 Accepted',
|
8
|
+
203 => '203 Non-Authoritative Information',
|
9
|
+
204 => '204 No Content',
|
10
|
+
205 => '205 Reset Content',
|
11
|
+
206 => '206 Partial Content',
|
12
|
+
300 => '300 Multiple Choices',
|
13
|
+
301 => '301 Moved Permanently',
|
14
|
+
304 => '304 Not Modified',
|
15
|
+
305 => '305 Use Proxy',
|
16
|
+
307 => '307 Temporary Redirect',
|
17
|
+
400 => '400 Bad Request',
|
18
|
+
401 => '401 Unauthorized',
|
19
|
+
402 => '402 Payment Required',
|
20
|
+
403 => '403 Forbidden',
|
21
|
+
404 => '404 Not Found',
|
22
|
+
405 => '405 Method Not Allowed',
|
23
|
+
406 => '406 Not Acceptable',
|
24
|
+
407 => '407 Proxy Authentication Required',
|
25
|
+
408 => '408 Request Time-out',
|
26
|
+
409 => '409 Conflict',
|
27
|
+
410 => '410 Gone',
|
28
|
+
411 => '411 Length Required',
|
29
|
+
412 => '412 Precondition Failed',
|
30
|
+
413 => '413 Request Entity Too Large',
|
31
|
+
414 => '414 Request-URI Too Large',
|
32
|
+
415 => '415 Unsupported Media Type',
|
33
|
+
416 => '416 Requested range not satisfiable',
|
34
|
+
417 => '417 Expectation Failed',
|
35
|
+
500 => '500 Internal Server Error',
|
36
|
+
501 => '501 Not Implemented',
|
37
|
+
502 => '502 Bad Gateway',
|
38
|
+
503 => '503 Service Unavailable',
|
39
|
+
504 => '504 Gateway Time-out',
|
40
|
+
505 => '505 HTTP Version not supported'
|
41
|
+
}
|
42
|
+
STATUS_CODE.default= '500 Internal Server Error'
|
43
|
+
STATUS_CODE.freeze
|
44
|
+
|
45
|
+
DEFAULT_HEADER = {
|
46
|
+
"Server" => "Midori/#{Midori::VERSION}"
|
47
|
+
}
|
48
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class String
|
2
|
+
def colorize(color_code)
|
3
|
+
"\e[#{color_code}m#{self}\e[0m"
|
4
|
+
end
|
5
|
+
|
6
|
+
def red
|
7
|
+
colorize(31)
|
8
|
+
end
|
9
|
+
|
10
|
+
def green
|
11
|
+
colorize(32)
|
12
|
+
end
|
13
|
+
|
14
|
+
def yellow
|
15
|
+
colorize(33)
|
16
|
+
end
|
17
|
+
|
18
|
+
def blue
|
19
|
+
colorize(34)
|
20
|
+
end
|
21
|
+
|
22
|
+
def pink
|
23
|
+
colorize(35)
|
24
|
+
end
|
25
|
+
|
26
|
+
def light_blue
|
27
|
+
colorize(36)
|
28
|
+
end
|
29
|
+
end
|
@@ -6,4 +6,11 @@ module Kernel #:nodoc:
|
|
6
6
|
Object.const_get(name).class_eval(&Proc.new) if block_given?
|
7
7
|
Object.const_get(name)
|
8
8
|
end
|
9
|
+
|
10
|
+
def define_error(*args)
|
11
|
+
args.each do |arg|
|
12
|
+
class_name = arg.to_s.split('_').map {|word| word[0] = word[0].upcase; word}.join
|
13
|
+
define_class(class_name, StandardError)
|
14
|
+
end
|
15
|
+
end
|
9
16
|
end
|
data/lib/em-midori/em_midori.rb
CHANGED
@@ -1,24 +1,23 @@
|
|
1
1
|
require 'eventmachine'
|
2
2
|
|
3
3
|
module Midori
|
4
|
-
def self.run(api=
|
4
|
+
def self.run(api=Midori::API, ip=nil, port=nil)
|
5
5
|
ip ||= '127.0.0.1'
|
6
6
|
port ||= 8081
|
7
7
|
EventMachine.run do
|
8
|
-
puts "Midori #{Midori::VERSION} is now running on #{ip}:#{port}"
|
9
|
-
Midori::Server
|
10
|
-
@midori_server = EventMachine.start_server ip, port, Midori::Server
|
8
|
+
puts "Midori #{Midori::VERSION} is now running on #{ip}:#{port}".blue
|
9
|
+
@midori_server = EventMachine.start_server ip, port, Midori::Server, api
|
11
10
|
end
|
12
11
|
end
|
13
12
|
|
14
13
|
def self.stop
|
15
14
|
if @midori_server.nil?
|
16
|
-
puts 'Midori Server has NOT been started'
|
15
|
+
puts 'Midori Server has NOT been started'.red
|
17
16
|
return false
|
18
17
|
else
|
19
18
|
EventMachine.stop_server(@midori_server)
|
20
19
|
@midori_server = nil
|
21
|
-
puts 'Goodbye Midori'
|
20
|
+
puts 'Goodbye Midori'.blue
|
22
21
|
return true
|
23
22
|
end
|
24
23
|
end
|
data/lib/em-midori/request.rb
CHANGED
@@ -1,3 +1,64 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
1
3
|
class Midori::Request
|
4
|
+
attr_accessor :ip, :port,
|
5
|
+
:protocol, :method, :path, :query_string,
|
6
|
+
:header, :body
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@parsed = false
|
10
|
+
@is_websocket = false
|
11
|
+
@is_eventsource = false
|
12
|
+
end
|
13
|
+
|
14
|
+
# Init an request with StringIO data
|
15
|
+
# === Attributes
|
16
|
+
# * +data+ [+StringIO+] - Request data
|
17
|
+
def parse(data)
|
18
|
+
@header = Hash.new
|
19
|
+
|
20
|
+
# Parse request
|
21
|
+
line = data.gets.split
|
22
|
+
@protocol = line[2]
|
23
|
+
@method = line[0]
|
24
|
+
@query_string = line[1].match(/\?(.*?)$/)
|
25
|
+
unless @query_string.nil?
|
26
|
+
@query_string = @query_string[1]
|
27
|
+
end
|
28
|
+
@path = line[1].gsub(/\?(.*?)$/, '')
|
29
|
+
|
30
|
+
# Parse header
|
31
|
+
while (line = data.gets) != "\r\n"
|
32
|
+
line = line.split
|
33
|
+
@header[line[0][0..-2]] = line[1..-1].join(' ')
|
34
|
+
end
|
35
|
+
|
36
|
+
# Deal with WebSocket
|
37
|
+
if @header['Upgrade'] == 'websocket' && @header['Connection'] == 'Upgrade'
|
38
|
+
@method = 'WEBSOCKET'
|
39
|
+
@is_websocket = true
|
40
|
+
end
|
41
|
+
|
42
|
+
# Deal with EventSource
|
43
|
+
if @header['Accept'] == 'text/event-stream'
|
44
|
+
@method = 'EVENTSOURCE'
|
45
|
+
@is_eventsource = true
|
46
|
+
end
|
47
|
+
|
48
|
+
# Parse body
|
49
|
+
@body = data.read
|
50
|
+
@parsed = true
|
51
|
+
end
|
52
|
+
|
53
|
+
def parsed?
|
54
|
+
@parsed
|
55
|
+
end
|
56
|
+
|
57
|
+
def websocket?
|
58
|
+
@is_websocket
|
59
|
+
end
|
2
60
|
|
61
|
+
def eventsource?
|
62
|
+
@is_eventsource
|
63
|
+
end
|
3
64
|
end
|
data/lib/em-midori/response.rb
CHANGED
@@ -1,56 +1,19 @@
|
|
1
1
|
class Midori::Response
|
2
|
-
|
3
|
-
100 => '100 Continue',
|
4
|
-
101 => '101 Switching Protocols',
|
5
|
-
200 => '200 OK',
|
6
|
-
201 => '201 Created',
|
7
|
-
202 => '202 Accepted',
|
8
|
-
203 => '203 Non-Authoritative Information',
|
9
|
-
204 => '204 No Content',
|
10
|
-
205 => '205 Reset Content',
|
11
|
-
206 => '206 Partial Content',
|
12
|
-
300 => '300 Multiple Choices',
|
13
|
-
301 => '301 Moved Permanently',
|
14
|
-
304 => '304 Not Modified',
|
15
|
-
305 => '305 Use Proxy',
|
16
|
-
307 => '307 Temporary Redirect',
|
17
|
-
400 => '400 Bad Request',
|
18
|
-
401 => '401 Unauthorized',
|
19
|
-
402 => '402 Payment Required',
|
20
|
-
403 => '403 Forbidden',
|
21
|
-
404 => '404 Not Found',
|
22
|
-
405 => '405 Method Not Allowed',
|
23
|
-
406 => '406 Not Acceptable',
|
24
|
-
407 => '407 Proxy Authentication Required',
|
25
|
-
408 => '408 Request Time-out',
|
26
|
-
409 => '409 Conflict',
|
27
|
-
410 => '410 Gone',
|
28
|
-
411 => '411 Length Required',
|
29
|
-
412 => '412 Precondition Failed',
|
30
|
-
413 => '413 Request Entity Too Large',
|
31
|
-
414 => '414 Request-URI Too Large',
|
32
|
-
415 => '415 Unsupported Media Type',
|
33
|
-
416 => '416 Requested range not satisfiable',
|
34
|
-
417 => '417 Expectation Failed',
|
35
|
-
500 => '500 Internal Server Error',
|
36
|
-
501 => '501 Not Implemented',
|
37
|
-
502 => '502 Bad Gateway',
|
38
|
-
503 => '503 Service Unavailable',
|
39
|
-
504 => '504 Gateway Time-out',
|
40
|
-
505 => '505 HTTP Version not supported'
|
41
|
-
}
|
42
|
-
STATUS_CODE.default= '500 Internal Server Error'
|
43
|
-
STATUS_CODE.freeze
|
2
|
+
attr_accessor :status, :header, :body
|
44
3
|
|
45
|
-
|
46
|
-
|
47
|
-
def initialize(code=200, header={}, body='')
|
48
|
-
@status_code = STATUS_CODE[code]
|
4
|
+
def initialize(code=200, header= Midori::Const::DEFAULT_HEADER, body='')
|
5
|
+
@status = Midori::Const::STATUS_CODE[code]
|
49
6
|
@header = header
|
50
7
|
@body = body
|
51
8
|
end
|
52
9
|
|
10
|
+
def generate_header
|
11
|
+
@header.map do |key, value|
|
12
|
+
"#{key}: #{value}\r\n"
|
13
|
+
end.join
|
14
|
+
end
|
15
|
+
|
53
16
|
def to_s
|
54
|
-
"HTTP/1.1 #{@
|
17
|
+
"HTTP/1.1 #{@status}\r\n#{generate_header}\r\n#{@body}"
|
55
18
|
end
|
56
19
|
end
|
data/lib/em-midori/server.rb
CHANGED
@@ -1,15 +1,78 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
1
3
|
module Midori::Server
|
2
|
-
|
3
|
-
|
4
|
+
attr_accessor :request, :api, :websocket
|
5
|
+
|
6
|
+
def initialize(api)
|
7
|
+
@api = api
|
8
|
+
@request = Midori::Request.new
|
9
|
+
@websocket = Midori::WebSocket.new(self)
|
4
10
|
end
|
5
11
|
|
6
12
|
def receive_data(data)
|
13
|
+
start_time = Time.now
|
14
|
+
data = StringIO.new(data)
|
7
15
|
port, ip = Socket.unpack_sockaddr_in(get_peername)
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
16
|
+
@request.ip = ip
|
17
|
+
@request.port = port
|
18
|
+
if @request.parsed?
|
19
|
+
websocket_request(data)
|
20
|
+
else
|
21
|
+
receive_new_request(data)
|
22
|
+
end
|
23
|
+
$stdout << "#{@request.ip} - - [#{Time.now.inspect}] \"#{@request.method} #{@request.path} #{@request.protocol}\" #{@response.status} #{(Time.now.to_f - start_time.to_f).round(5)}\n".green
|
14
24
|
end
|
25
|
+
|
26
|
+
def receive_new_request(data)
|
27
|
+
begin
|
28
|
+
@request.parse(data)
|
29
|
+
@response = @api.receive(request, self)
|
30
|
+
rescue Midori::Error::NotFound => _e
|
31
|
+
@response = Midori::Response.new(404, {}, '404 Not Found')
|
32
|
+
rescue => e
|
33
|
+
@response = Midori::Response.new(500, {}, 'Internal Server Error')
|
34
|
+
puts e.inspect.yellow
|
35
|
+
end
|
36
|
+
unless (@request.websocket? || @request.eventsource?)
|
37
|
+
send_data @response
|
38
|
+
close_connection_after_writing
|
39
|
+
end
|
40
|
+
if @request.websocket? && !@websocket.events[:open].nil?
|
41
|
+
call_event(:open)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def websocket_request(data)
|
46
|
+
begin
|
47
|
+
@websocket.decode(data)
|
48
|
+
case @websocket.opcode
|
49
|
+
when 0x1, 0x2
|
50
|
+
call_event(:message, @websocket.msg)
|
51
|
+
when 0x9
|
52
|
+
call_event(:ping)
|
53
|
+
@websocket.pong
|
54
|
+
when 0xA
|
55
|
+
call_event(:pong)
|
56
|
+
else
|
57
|
+
# Unknown Control Frame
|
58
|
+
raise Midori::Error::FrameEnd
|
59
|
+
end
|
60
|
+
rescue Midori::Error::FrameEnd => _e
|
61
|
+
unless @websocket.events[:close].nil?
|
62
|
+
call_event(:close)
|
63
|
+
end
|
64
|
+
send_data "\b" # Opcode 0x8
|
65
|
+
close_connection_after_writing
|
66
|
+
rescue => e
|
67
|
+
puts e.inspect.yellow
|
68
|
+
@response = Midori::Response.new(400, {}, 'Bad Request')
|
69
|
+
send_data @response
|
70
|
+
close_connection_after_writing
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def call_event(event, args=[])
|
75
|
+
lambda {@websocket.instance_exec(*args, &@websocket.events[event])}.call unless @websocket.events[event].nil?
|
76
|
+
end
|
77
|
+
|
15
78
|
end
|
data/lib/em-midori/version.rb
CHANGED
@@ -0,0 +1,63 @@
|
|
1
|
+
class Midori::WebSocket
|
2
|
+
attr_accessor :msg, :opcode, :events, :connection
|
3
|
+
|
4
|
+
def initialize(connection)
|
5
|
+
@events = Hash.new
|
6
|
+
@connection = connection
|
7
|
+
end
|
8
|
+
|
9
|
+
def decode(data)
|
10
|
+
# Fin and Opcode
|
11
|
+
byte_tmp = data.getbyte
|
12
|
+
fin = byte_tmp & 0b10000000
|
13
|
+
@opcode = byte_tmp & 0b00001111
|
14
|
+
raise Midori::Error::ContinuousFrame unless fin
|
15
|
+
raise Midori::Error::OpCodeError unless [0x1, 0x2, 0x8, 0x9, 0xA].include?opcode
|
16
|
+
raise Midori::Error::FrameEnd if @opcode == 0x8 # Close Frame
|
17
|
+
return if @opcode == 0x9 || @opcode == 0xA # Ping Pong
|
18
|
+
decode_mask(data)
|
19
|
+
end
|
20
|
+
|
21
|
+
def decode_mask(data)
|
22
|
+
# Mask
|
23
|
+
byte_tmp = data.getbyte
|
24
|
+
is_masked = byte_tmp & 0b10000000
|
25
|
+
raise Midori::Error::NotMasked unless is_masked
|
26
|
+
# Payload
|
27
|
+
payload = byte_tmp & 0b01111111
|
28
|
+
mask = 4.times.map {data.getbyte}
|
29
|
+
# Message
|
30
|
+
masked_msg = payload.times.map {data.getbyte}
|
31
|
+
@msg = masked_msg.each_with_index.map {|byte, i| byte ^ mask[i % 4]}
|
32
|
+
@msg = @msg.pack('C*').force_encoding('utf-8') if @opcode == 0x1
|
33
|
+
end
|
34
|
+
|
35
|
+
def on(event, &block) # open, message, close, ping, pong
|
36
|
+
@events[event] = block
|
37
|
+
end
|
38
|
+
|
39
|
+
def send(msg)
|
40
|
+
output = Array.new
|
41
|
+
if msg.is_a?String
|
42
|
+
output << 0b10000001 << msg.size << msg
|
43
|
+
elsif msg.is_a?Array
|
44
|
+
output << 0b10000010 << msg.size
|
45
|
+
output.concat msg
|
46
|
+
else
|
47
|
+
raise Midori::Error::OpCodeError
|
48
|
+
end
|
49
|
+
@connection.send_data(output.pack("CCA#{msg.size}"))
|
50
|
+
end
|
51
|
+
|
52
|
+
def ping
|
53
|
+
@connection.send_data "\t"
|
54
|
+
end
|
55
|
+
|
56
|
+
def pong
|
57
|
+
@connection.send_data "\n"
|
58
|
+
end
|
59
|
+
|
60
|
+
def close
|
61
|
+
Midori::Error::FrameEnd
|
62
|
+
end
|
63
|
+
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.
|
4
|
+
version: 0.0.6
|
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-
|
11
|
+
date: 2016-10-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: eventmachine
|
@@ -72,6 +72,20 @@ dependencies:
|
|
72
72
|
- - "~>"
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: '3.0'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: faye-websocket
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0.10'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0.10'
|
75
89
|
description: An EventMachine Based Web Framework on Ruby
|
76
90
|
email: business@heckpsi.com
|
77
91
|
executables: []
|
@@ -82,6 +96,7 @@ files:
|
|
82
96
|
- ".gitignore"
|
83
97
|
- ".resources/midori_tokiwa.gif"
|
84
98
|
- ".resources/sapphire_kawashima.gif"
|
99
|
+
- ".resources/slogan.png"
|
85
100
|
- ".rspec"
|
86
101
|
- ".rubocop.yml"
|
87
102
|
- ".travis.yml"
|
@@ -89,12 +104,17 @@ files:
|
|
89
104
|
- lib/em-midori.rb
|
90
105
|
- lib/em-midori/api.rb
|
91
106
|
- lib/em-midori/clean_room.rb
|
107
|
+
- lib/em-midori/const.rb
|
108
|
+
- lib/em-midori/debug.rb
|
92
109
|
- lib/em-midori/define_class.rb
|
93
110
|
- lib/em-midori/em_midori.rb
|
111
|
+
- lib/em-midori/error.rb
|
94
112
|
- lib/em-midori/request.rb
|
95
113
|
- lib/em-midori/response.rb
|
114
|
+
- lib/em-midori/route.rb
|
96
115
|
- lib/em-midori/server.rb
|
97
116
|
- lib/em-midori/version.rb
|
117
|
+
- lib/em-midori/websocket.rb
|
98
118
|
homepage: https://github.com/heckpsi-lab/em-midori
|
99
119
|
licenses:
|
100
120
|
- MIT
|
@@ -120,3 +140,4 @@ signing_key:
|
|
120
140
|
specification_version: 4
|
121
141
|
summary: An EventMachine Based Web Framework on Ruby
|
122
142
|
test_files: []
|
143
|
+
has_rdoc:
|