rakie 0.0.3 → 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rakie.rb +13 -1
- data/lib/rakie/channel.rb +9 -3
- data/lib/rakie/event.rb +28 -9
- data/lib/rakie/http.rb +5 -0
- data/lib/rakie/http_proto.rb +197 -0
- data/lib/rakie/http_server.rb +127 -0
- data/lib/rakie/log.rb +96 -0
- data/lib/rakie/proto.rb +63 -0
- data/lib/rakie/tcp_channel.rb +19 -3
- data/lib/rakie/tcp_server_channel.rb +27 -11
- data/lib/rakie/version.rb +11 -0
- data/lib/rakie/websocket.rb +137 -0
- data/lib/rakie/websocket_proto.rb +286 -0
- data/lib/rakie/websocket_server.rb +83 -0
- metadata +10 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 754086391c9ec9e2eb623d8d6a1ead9ca9188d49fb0c391b26c4a9e36db88236
|
4
|
+
data.tar.gz: 6ac34e0868c8bc1748e7f572266b4223a91f676d9d7c11b22fa5a7e10586713c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 839acbd5155b745948a6144a37480b770e50f01ff4daf29146e39c8fb2e36cf0f434f10313577d3f7b1efcfd039317b036d9c87f96d6c57d09a25c9da6ba5e10
|
7
|
+
data.tar.gz: a844de019fa10103c96e7cc7ab4f7e78ffb2cd5a7c23b28be6483c35fbb7a5cfd1b51f4a1996fa053fa33e03d701af52682c0af306d92b3f2c2c98878aa7c4c6
|
data/lib/rakie.rb
CHANGED
@@ -1,12 +1,24 @@
|
|
1
1
|
|
2
2
|
module Rakie
|
3
|
-
|
3
|
+
NAME = "rakie"
|
4
|
+
MODE_DEV = 0
|
5
|
+
MODE_REL = 1
|
6
|
+
|
7
|
+
def self.current_mode
|
8
|
+
@current_mode ||= MODE_REL
|
9
|
+
end
|
4
10
|
end
|
5
11
|
|
6
12
|
require "rakie/channel"
|
7
13
|
require "rakie/event"
|
14
|
+
require "rakie/proto"
|
15
|
+
require "rakie/http_proto"
|
16
|
+
require "rakie/websocket_proto"
|
8
17
|
require "rakie/simple_server"
|
9
18
|
require "rakie/http_server"
|
19
|
+
require "rakie/websocket"
|
20
|
+
require "rakie/websocket_server"
|
10
21
|
require "rakie/tcp_channel"
|
11
22
|
require "rakie/tcp_server_channel"
|
12
23
|
require "rakie/log"
|
24
|
+
require "rakie/version"
|
data/lib/rakie/channel.rb
CHANGED
@@ -2,6 +2,8 @@ module Rakie
|
|
2
2
|
class Channel
|
3
3
|
attr_accessor :delegate
|
4
4
|
|
5
|
+
DEFAULT_BUFFER_SIZE = 512 * 1024
|
6
|
+
|
5
7
|
def initialize(io, delegate=nil)
|
6
8
|
@io = io
|
7
9
|
@read_buffer = String.new
|
@@ -14,7 +16,7 @@ module Rakie
|
|
14
16
|
def on_read(io)
|
15
17
|
begin
|
16
18
|
loop do
|
17
|
-
@read_buffer << io.read_nonblock(
|
19
|
+
@read_buffer << io.read_nonblock(DEFAULT_BUFFER_SIZE)
|
18
20
|
end
|
19
21
|
|
20
22
|
rescue IO::EAGAINWaitReadable
|
@@ -32,6 +34,7 @@ module Rakie
|
|
32
34
|
end
|
33
35
|
|
34
36
|
if @delegate != nil
|
37
|
+
Log.debug("Channel handle on_recv")
|
35
38
|
len = @delegate.on_recv(self, @read_buffer)
|
36
39
|
|
37
40
|
if len > @read_buffer.length
|
@@ -39,7 +42,6 @@ module Rakie
|
|
39
42
|
end
|
40
43
|
|
41
44
|
@read_buffer = @read_buffer[len .. -1]
|
42
|
-
Log.debug("Channel handle on_recv")
|
43
45
|
end
|
44
46
|
|
45
47
|
return Event::HANDLE_CONTINUED
|
@@ -90,10 +92,14 @@ module Rakie
|
|
90
92
|
return Event::HANDLE_FINISHED
|
91
93
|
end
|
92
94
|
|
93
|
-
def
|
95
|
+
def on_detach(io)
|
94
96
|
begin
|
95
97
|
io.close
|
96
98
|
|
99
|
+
if @delegate
|
100
|
+
@delegate.on_close(self)
|
101
|
+
end
|
102
|
+
|
97
103
|
rescue
|
98
104
|
Log.debug("Channel is already closed")
|
99
105
|
end
|
data/lib/rakie/event.rb
CHANGED
@@ -50,7 +50,7 @@ module Rakie
|
|
50
50
|
|
51
51
|
if handler != nil
|
52
52
|
Log.debug("Event close #{new_io}")
|
53
|
-
handler.
|
53
|
+
handler.on_detach(new_io)
|
54
54
|
end
|
55
55
|
|
56
56
|
@ios.delete(new_io)
|
@@ -105,11 +105,11 @@ module Rakie
|
|
105
105
|
result = handler.on_read(io)
|
106
106
|
|
107
107
|
if result == HANDLE_FINISHED
|
108
|
-
@ios[io]
|
108
|
+
@ios[io] &= ~READ_EVENT
|
109
109
|
Log.debug("Event remove read #{io}")
|
110
110
|
|
111
111
|
elsif result == HANDLE_FAILED
|
112
|
-
handler.
|
112
|
+
handler.on_detach(io)
|
113
113
|
Log.debug("Event close #{io}")
|
114
114
|
|
115
115
|
@ios.delete(io)
|
@@ -130,11 +130,11 @@ module Rakie
|
|
130
130
|
result = handler.on_write(io)
|
131
131
|
|
132
132
|
if result == HANDLE_FINISHED
|
133
|
-
@ios[io]
|
133
|
+
@ios[io] &= ~WRITE_EVENT
|
134
134
|
Log.debug("Event remove write #{io}")
|
135
135
|
|
136
136
|
elsif result == HANDLE_FAILED
|
137
|
-
handler.
|
137
|
+
handler.on_detach(io)
|
138
138
|
Log.debug("Event close #{io}")
|
139
139
|
|
140
140
|
@ios.delete(io)
|
@@ -168,19 +168,38 @@ module Rakie
|
|
168
168
|
end
|
169
169
|
|
170
170
|
def self.instance
|
171
|
-
@instance ||= Event.new
|
171
|
+
@instance ||= Array.new(self.concurrent) { |i| Event.new }
|
172
172
|
end
|
173
173
|
|
174
174
|
def self.push(io, listener, type)
|
175
|
-
|
175
|
+
i = io.fileno % self.concurrent
|
176
|
+
inst = self.instance[i]
|
177
|
+
inst.push(io, listener, type)
|
178
|
+
# instance.push(io, listener, type)
|
176
179
|
end
|
177
180
|
|
178
181
|
def self.delete(io)
|
179
|
-
self.
|
182
|
+
i = io.fileno % self.concurrent
|
183
|
+
inst = self.instance[i]
|
184
|
+
inst.delete(io)
|
185
|
+
# self.instance.delete(io)
|
180
186
|
end
|
181
187
|
|
182
188
|
def self.modify(io, listener, type)
|
183
|
-
|
189
|
+
i = io.fileno % self.concurrent
|
190
|
+
inst = self.instance[i]
|
191
|
+
inst.modify(io, listener, type)
|
192
|
+
# self.instance.modify(io, listener, type)
|
193
|
+
end
|
194
|
+
|
195
|
+
# @return [Integer]
|
196
|
+
def self.concurrent
|
197
|
+
@concurrent ||= 2
|
198
|
+
end
|
199
|
+
|
200
|
+
# @param [Integer] count
|
201
|
+
def self.concurrent=(count)
|
202
|
+
@concurrent = count
|
184
203
|
end
|
185
204
|
end
|
186
205
|
end
|
@@ -0,0 +1,197 @@
|
|
1
|
+
module Rakie
|
2
|
+
class HttpMIME
|
3
|
+
TEXT = "text/plain"
|
4
|
+
HTML = "text/html"
|
5
|
+
JSON = "application/json"
|
6
|
+
end
|
7
|
+
|
8
|
+
class HttpRequest
|
9
|
+
include Proto
|
10
|
+
|
11
|
+
attr_accessor :head, :headers, :content
|
12
|
+
|
13
|
+
PARSE_HEAD = PARSE_BEGIN
|
14
|
+
PARSE_HEADERS = 1
|
15
|
+
PARSE_CONTENT = 2
|
16
|
+
|
17
|
+
class Head
|
18
|
+
attr_accessor :method, :path, :version
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
@method = 'HEAD'
|
22
|
+
@path = '/'
|
23
|
+
@version = 'HTTP/1.1'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize
|
28
|
+
@head = Head.new
|
29
|
+
@headers = {}
|
30
|
+
@content = ''
|
31
|
+
end
|
32
|
+
|
33
|
+
# @param [String] source
|
34
|
+
def parse_source_head(source)
|
35
|
+
offset = parse_offset
|
36
|
+
|
37
|
+
if eol_offset = source.index("\r\n")
|
38
|
+
head_s = source[0 .. eol_offset]
|
39
|
+
head_method, head_path, head_version = head_s.split(' ')
|
40
|
+
|
41
|
+
head.method = head_method
|
42
|
+
head.path = head_path
|
43
|
+
head.version = head_version
|
44
|
+
|
45
|
+
self.parse_state = PARSE_HEADERS
|
46
|
+
self.parse_offset = offset + 2
|
47
|
+
|
48
|
+
Log.debug("Rakie::HttpRequest parse source head ok")
|
49
|
+
return ParseStatus::CONTINUE
|
50
|
+
end
|
51
|
+
|
52
|
+
return ParseStatus::PENDING
|
53
|
+
end
|
54
|
+
|
55
|
+
def parse_source_header_item(header)
|
56
|
+
if semi_offset = header.index(':')
|
57
|
+
return [
|
58
|
+
header[0 .. (semi_offset - 1)].downcase,
|
59
|
+
header[(semi_offset + 1) .. -1].strip
|
60
|
+
]
|
61
|
+
end
|
62
|
+
|
63
|
+
return nil
|
64
|
+
end
|
65
|
+
|
66
|
+
# @param [String] source
|
67
|
+
def parse_source_headers(source)
|
68
|
+
offset = parse_offset
|
69
|
+
|
70
|
+
while eol_offset = source.index("\r\n", offset)
|
71
|
+
header = source[offset .. (eol_offset - 1)]
|
72
|
+
|
73
|
+
if header.length == 0
|
74
|
+
self.parse_state = PARSE_CONTENT
|
75
|
+
self.parse_offset = eol_offset + 2
|
76
|
+
|
77
|
+
Log.debug("Rakie::HttpRequest parse source header done")
|
78
|
+
return ParseStatus::CONTINUE
|
79
|
+
end
|
80
|
+
|
81
|
+
header_key, header_value = self.parse_source_header_item(header)
|
82
|
+
|
83
|
+
if header_key
|
84
|
+
headers[header_key] = header_value
|
85
|
+
Log.debug("Rakie::HttpRequest parse source #{header_key}, #{header_value} header ok")
|
86
|
+
end
|
87
|
+
|
88
|
+
offset = eol_offset + 2
|
89
|
+
end
|
90
|
+
|
91
|
+
self.parse_offset = offset
|
92
|
+
|
93
|
+
return ParseStatus::PENDING
|
94
|
+
end
|
95
|
+
|
96
|
+
# @param [String] source
|
97
|
+
def parse_source_content(source)
|
98
|
+
len = headers["content-length"]
|
99
|
+
offset = parse_offset
|
100
|
+
|
101
|
+
if len == nil
|
102
|
+
return ParseStatus::COMPLETE
|
103
|
+
end
|
104
|
+
|
105
|
+
len = len.to_i
|
106
|
+
|
107
|
+
if source.length >= len + offset
|
108
|
+
self.content = source[offset .. (offset + len - 1)]
|
109
|
+
self.parse_state = PARSE_HEAD
|
110
|
+
self.parse_offset = offset + len
|
111
|
+
|
112
|
+
Log.debug("Rakie::HttpRequest parse source content ok")
|
113
|
+
return ParseStatus::COMPLETE
|
114
|
+
end
|
115
|
+
|
116
|
+
return ParseStatus::PENDING
|
117
|
+
end
|
118
|
+
|
119
|
+
# @param [String] source
|
120
|
+
# @return [Integer]
|
121
|
+
def deserialize(source)
|
122
|
+
current_state = parse_state
|
123
|
+
|
124
|
+
case current_state
|
125
|
+
when PARSE_HEAD
|
126
|
+
return parse_source_head(source)
|
127
|
+
|
128
|
+
when PARSE_HEADERS
|
129
|
+
return parse_source_headers(source)
|
130
|
+
|
131
|
+
when PARSE_CONTENT
|
132
|
+
return parse_source_content(source)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# @return [String]
|
137
|
+
def serialize
|
138
|
+
data = ""
|
139
|
+
|
140
|
+
data += "#{head.method} #{head.path} #{head.version}"
|
141
|
+
data += "\r\n"
|
142
|
+
|
143
|
+
headers_list = []
|
144
|
+
headers.each do |k, v|
|
145
|
+
headers_list << "#{k}: #{v}"
|
146
|
+
end
|
147
|
+
|
148
|
+
data += headers_list.join("\r\n")
|
149
|
+
data += "\r\n\r\n"
|
150
|
+
|
151
|
+
data += content
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
class HttpResponse
|
156
|
+
include Proto
|
157
|
+
|
158
|
+
PARSE_HEAD = 0
|
159
|
+
PARSE_HEADERS = 1
|
160
|
+
PARSE_CONTENT = 2
|
161
|
+
|
162
|
+
attr_accessor :head, :headers, :content
|
163
|
+
|
164
|
+
class Head
|
165
|
+
attr_accessor :version, :status, :message
|
166
|
+
|
167
|
+
def initialize
|
168
|
+
@version = 'HTTP/1.1'
|
169
|
+
@status = 200
|
170
|
+
@message = 'OK'
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def initialize
|
175
|
+
@head = Head.new
|
176
|
+
@headers = {}
|
177
|
+
@content = ''
|
178
|
+
end
|
179
|
+
|
180
|
+
def serialize
|
181
|
+
data = ""
|
182
|
+
|
183
|
+
data += "#{head.version} #{head.status} #{head.message}"
|
184
|
+
data += "\r\n"
|
185
|
+
|
186
|
+
headers_list = []
|
187
|
+
headers.each do |k, v|
|
188
|
+
headers_list << "#{k}: #{v}"
|
189
|
+
end
|
190
|
+
|
191
|
+
data += headers_list.join("\r\n")
|
192
|
+
data += "\r\n\r\n"
|
193
|
+
|
194
|
+
data += content
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module Rakie
|
2
|
+
class HttpServer
|
3
|
+
class Session
|
4
|
+
# @return [HttpRequest]
|
5
|
+
attr_accessor :request
|
6
|
+
|
7
|
+
# @type [Array<HttpResponse>]
|
8
|
+
attr_accessor :responses
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@request = HttpRequest.new
|
12
|
+
@responses = []
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :channel, :opt
|
17
|
+
|
18
|
+
def initialize(delegate=nil)
|
19
|
+
@channel = TCPServerChannel.new('127.0.0.1', 10086, self)
|
20
|
+
|
21
|
+
# @type [Hash{Channel=>Session}]
|
22
|
+
@sessions = {}
|
23
|
+
@delegate = delegate
|
24
|
+
@opt = {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def on_accept(channel)
|
28
|
+
channel.delegate = self
|
29
|
+
@sessions[channel] = Session.new
|
30
|
+
Log.debug("Rakie::HTTPServer accept client: #{channel}")
|
31
|
+
end
|
32
|
+
|
33
|
+
def on_recv(channel, data)
|
34
|
+
# Log.debug("Rakie::HTTPServer recv: #{data}")
|
35
|
+
session = @sessions[channel]
|
36
|
+
|
37
|
+
if session == nil
|
38
|
+
return 0
|
39
|
+
end
|
40
|
+
|
41
|
+
# @type [HttpRequest] request
|
42
|
+
request = session.request
|
43
|
+
|
44
|
+
if request.parse_status == ParseStatus::COMPLETE
|
45
|
+
request = HttpRequest.new
|
46
|
+
session.request = request
|
47
|
+
end
|
48
|
+
|
49
|
+
len = request.parse(data)
|
50
|
+
|
51
|
+
Log.debug("Rakie::HttpServer receive request: #{request.to_s}")
|
52
|
+
|
53
|
+
if request.parse_status == ParseStatus::COMPLETE
|
54
|
+
response = HttpResponse.new
|
55
|
+
|
56
|
+
if upgrade = request.headers["upgrade"]
|
57
|
+
if websocket_delegate = @opt[:websocket_delegate]
|
58
|
+
websocket_delegate.upgrade(request, response)
|
59
|
+
Log.debug("Rakie::HttpServer upgrade protocol")
|
60
|
+
end
|
61
|
+
|
62
|
+
elsif @delegate != nil
|
63
|
+
@delegate.handle(request, response)
|
64
|
+
|
65
|
+
else
|
66
|
+
response.headers["content-type"] = HttpMIME::HTML
|
67
|
+
response.content = "<html><body><h1>Rakie!</h1></body></html>"
|
68
|
+
end
|
69
|
+
|
70
|
+
if header_connection = request.headers["connection"]
|
71
|
+
response.headers["connection"] = header_connection
|
72
|
+
end
|
73
|
+
|
74
|
+
if response.content.length > 0
|
75
|
+
response.headers["content-length"] = response.content.length
|
76
|
+
end
|
77
|
+
|
78
|
+
response.headers["server"] = Rakie.full_version_s
|
79
|
+
session.responses << response
|
80
|
+
response_data = response.to_s
|
81
|
+
|
82
|
+
Log.debug("Rakie::HttpServer response: #{response_data}")
|
83
|
+
|
84
|
+
channel.write(response_data) # Response data
|
85
|
+
|
86
|
+
elsif request.parse_status == ParseStatus::ERROR
|
87
|
+
channel.close
|
88
|
+
@sessions.delete(channel)
|
89
|
+
|
90
|
+
Log.debug("Rakie::HttpServer: Illegal request")
|
91
|
+
return len
|
92
|
+
end
|
93
|
+
|
94
|
+
return len
|
95
|
+
end
|
96
|
+
|
97
|
+
def on_send(channel)
|
98
|
+
session = @sessions[channel]
|
99
|
+
# @type [HttpRequest]
|
100
|
+
last_response = session.responses.shift
|
101
|
+
|
102
|
+
if last_response
|
103
|
+
if connect_status = last_response.headers["connection"]
|
104
|
+
if connect_status.downcase == "close"
|
105
|
+
Log.debug("Rakie::HttpServer: send finish and close channel")
|
106
|
+
channel.close
|
107
|
+
@sessions.delete(channel)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
if upgrade = last_response.headers["upgrade"]
|
112
|
+
websocket_delegate = @opt[:websocket_delegate]
|
113
|
+
|
114
|
+
if websocket_delegate
|
115
|
+
websocket_delegate.on_accept(channel)
|
116
|
+
@sessions.delete(channel)
|
117
|
+
return
|
118
|
+
end
|
119
|
+
|
120
|
+
Log.debug("Rakie::HttpServer: no websocket delegate and close channel")
|
121
|
+
channel.close
|
122
|
+
@sessions.delete(channel)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
data/lib/rakie/log.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
module Rakie
|
2
|
+
class Log
|
3
|
+
attr_accessor :out, :level
|
4
|
+
|
5
|
+
@instance = nil
|
6
|
+
|
7
|
+
LEVEL_INFO = 0
|
8
|
+
LEVEL_ERROR = 1
|
9
|
+
LEVEL_DEBUG = 2
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@level = Rakie.current_mode == Rakie::MODE_DEV ? LEVEL_DEBUG : LEVEL_ERROR
|
13
|
+
@out = STDOUT
|
14
|
+
end
|
15
|
+
|
16
|
+
def level_text(level=nil)
|
17
|
+
unless level
|
18
|
+
level = @level
|
19
|
+
end
|
20
|
+
|
21
|
+
case level
|
22
|
+
when LEVEL_INFO
|
23
|
+
return "INFO"
|
24
|
+
|
25
|
+
when LEVEL_ERROR
|
26
|
+
return "ERROR"
|
27
|
+
|
28
|
+
when LEVEL_DEBUG
|
29
|
+
return "DEBUG"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def level_info?
|
34
|
+
@level >= LEVEL_INFO
|
35
|
+
end
|
36
|
+
|
37
|
+
def level_error?
|
38
|
+
@level >= LEVEL_ERROR
|
39
|
+
end
|
40
|
+
|
41
|
+
def level_debug?
|
42
|
+
@level >= LEVEL_DEBUG
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.instance
|
46
|
+
@instance ||= Log.new
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.info(message, who=nil)
|
50
|
+
unless self.instance.level_info?
|
51
|
+
return
|
52
|
+
end
|
53
|
+
|
54
|
+
if who
|
55
|
+
message = "#{who}: #{message}"
|
56
|
+
end
|
57
|
+
|
58
|
+
level = self.instance.level_text(LEVEL_INFO)
|
59
|
+
self.instance.out.write("[#{Time.now.to_s}][#{level}] #{message}\n")
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.error(message, who=nil)
|
63
|
+
unless self.instance.level_error?
|
64
|
+
return
|
65
|
+
end
|
66
|
+
|
67
|
+
if who
|
68
|
+
message = "#{who}: #{message}"
|
69
|
+
end
|
70
|
+
|
71
|
+
level = self.instance.level_text(LEVEL_ERROR)
|
72
|
+
self.instance.out.write("[#{Time.now.to_s}][#{level}] #{message}\n")
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.debug(message, who=nil)
|
76
|
+
unless self.instance.level_debug?
|
77
|
+
return
|
78
|
+
end
|
79
|
+
|
80
|
+
if who
|
81
|
+
message = "#{who}: #{message}"
|
82
|
+
end
|
83
|
+
|
84
|
+
level = self.instance.level_text(LEVEL_DEBUG)
|
85
|
+
self.instance.out.print("[#{Time.now.to_s}][#{level}] #{message}\n")
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.level
|
89
|
+
self.instance.level
|
90
|
+
end
|
91
|
+
|
92
|
+
def self.level=(level)
|
93
|
+
self.instance.level = level
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
data/lib/rakie/proto.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
module Rakie
|
2
|
+
class ParseStatus
|
3
|
+
ERROR = -1
|
4
|
+
CONTINUE = 0
|
5
|
+
PENDING = 1
|
6
|
+
COMPLETE = 2
|
7
|
+
end
|
8
|
+
|
9
|
+
module Proto
|
10
|
+
PARSE_BEGIN = 0
|
11
|
+
|
12
|
+
# @return [Integer]
|
13
|
+
def parse_status
|
14
|
+
@parse_status ||= ParseStatus::CONTINUE
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [Integer]
|
18
|
+
def parse_state
|
19
|
+
@parse_state ||= PARSE_BEGIN
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param [Integer] state
|
23
|
+
def parse_state=(state)
|
24
|
+
@parse_state = state
|
25
|
+
# puts("Set state: #{@parse_state}")
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [Integer]
|
29
|
+
def parse_offset
|
30
|
+
@parse_offset ||= 0
|
31
|
+
end
|
32
|
+
|
33
|
+
# @param [Integer] offset
|
34
|
+
def parse_offset=(offset)
|
35
|
+
@parse_offset = offset
|
36
|
+
end
|
37
|
+
|
38
|
+
# @param [String] source
|
39
|
+
def parse(source)
|
40
|
+
status = ParseStatus::CONTINUE
|
41
|
+
|
42
|
+
while status == ParseStatus::CONTINUE
|
43
|
+
status = self.deserialize(source)
|
44
|
+
end
|
45
|
+
|
46
|
+
if status == ParseStatus::PENDING
|
47
|
+
status = ParseStatus::CONTINUE
|
48
|
+
end
|
49
|
+
|
50
|
+
offset = @parse_offset
|
51
|
+
@parse_status = status
|
52
|
+
@parse_offset = 0
|
53
|
+
|
54
|
+
return offset
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param [Object] object
|
58
|
+
# @return [String]
|
59
|
+
def to_s
|
60
|
+
self.serialize
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/rakie/tcp_channel.rb
CHANGED
@@ -1,8 +1,24 @@
|
|
1
1
|
module Rakie
|
2
2
|
class TCPChannel < Channel
|
3
|
-
|
4
|
-
|
5
|
-
|
3
|
+
LOCAL_HOST = '127.0.0.1'
|
4
|
+
|
5
|
+
# @param host [String]
|
6
|
+
# @param port [Integer]
|
7
|
+
# @param delegate [Object]
|
8
|
+
# @param socket [Socket]
|
9
|
+
# @overload initialize(host, port, delegate)
|
10
|
+
# @overload initialize(host, port)
|
11
|
+
# @overload initialize(host, port, delegate, socket)
|
12
|
+
def initialize(host=LOCAL_HOST, port=3001, delegate=nil, socket=nil)
|
13
|
+
if socket == nil
|
14
|
+
socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
|
15
|
+
socket.connect(Socket.pack_sockaddr_in(port, host))
|
16
|
+
end
|
17
|
+
|
18
|
+
@port = port
|
19
|
+
@host = host
|
20
|
+
|
21
|
+
super(socket, delegate)
|
6
22
|
end
|
7
23
|
end
|
8
24
|
end
|
@@ -1,25 +1,41 @@
|
|
1
1
|
module Rakie
|
2
|
-
class TCPServerChannel <
|
3
|
-
|
4
|
-
|
2
|
+
class TCPServerChannel < TCPChannel
|
3
|
+
# @param host [String]
|
4
|
+
# @param port [Integer]
|
5
|
+
# @param delegate [Object]
|
6
|
+
# @overload initialize(host, port, delegate)
|
7
|
+
# @overload initialize(host, port)
|
8
|
+
# @overload initialize(port)
|
9
|
+
def initialize(host=LOCAL_HOST, port=3001, delegate=nil)
|
10
|
+
socket = nil
|
5
11
|
|
6
12
|
if port == nil
|
7
|
-
port =
|
8
|
-
|
9
|
-
|
10
|
-
else
|
11
|
-
io = TCPServer.new(ip, port)
|
13
|
+
port = host
|
14
|
+
host = LOCAL_HOST
|
12
15
|
end
|
13
16
|
|
17
|
+
socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM)
|
18
|
+
socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)
|
19
|
+
socket.bind(Socket.pack_sockaddr_in(port, host))
|
20
|
+
socket.listen(255)
|
21
|
+
|
14
22
|
@clients = []
|
15
23
|
|
16
|
-
super(
|
24
|
+
super(host, port, delegate, socket)
|
17
25
|
end
|
18
26
|
|
27
|
+
# @param io [Socket]
|
19
28
|
def on_read(io)
|
20
29
|
begin
|
21
|
-
|
22
|
-
|
30
|
+
ret = io.accept_nonblock
|
31
|
+
# @type client_io [Socket]
|
32
|
+
client_io = ret[0]
|
33
|
+
# @type client_info [Addrinfo]
|
34
|
+
client_info = ret[1]
|
35
|
+
client_name_info = client_info.getnameinfo
|
36
|
+
client_host = client_name_info[0]
|
37
|
+
client_port = client_name_info[1]
|
38
|
+
channel = TCPChannel.new(client_host, client_port, nil, client_io)
|
23
39
|
|
24
40
|
if @delegate != nil
|
25
41
|
Log.debug("TCPServerChannel has delegate")
|
@@ -0,0 +1,137 @@
|
|
1
|
+
module Rakie
|
2
|
+
class Websocket
|
3
|
+
attr_accessor :delegate, :client_side
|
4
|
+
attr_reader :channel
|
5
|
+
|
6
|
+
# @param [Rakie::TCPChannel] channel
|
7
|
+
def initialize(delegate=nil, channel=nil)
|
8
|
+
@delegate = delegate
|
9
|
+
|
10
|
+
if channel == nil
|
11
|
+
channel = TCPChannel.new('127.0.0.1', 10086, self)
|
12
|
+
end
|
13
|
+
|
14
|
+
@channel = channel
|
15
|
+
|
16
|
+
# @type [WebsocketMessage]
|
17
|
+
@recv_message = WebsocketMessage.new
|
18
|
+
|
19
|
+
# @type [Array<WebsocketMessage>]
|
20
|
+
@send_messages = []
|
21
|
+
@client_side = true
|
22
|
+
end
|
23
|
+
|
24
|
+
def on_recv(channel, data)
|
25
|
+
# Log.debug("Rakie::HTTPServer recv: #{data}")
|
26
|
+
|
27
|
+
# @type [WebsocketMessage] request
|
28
|
+
message = @recv_message
|
29
|
+
|
30
|
+
if message.parse_status == ParseStatus::COMPLETE
|
31
|
+
message = WebsocketMessage.new
|
32
|
+
@recv_message = message
|
33
|
+
end
|
34
|
+
|
35
|
+
len = message.parse(data)
|
36
|
+
|
37
|
+
Log.debug("Rakie::Websocket receive message: #{message.to_s}")
|
38
|
+
|
39
|
+
if message.parse_status == ParseStatus::COMPLETE
|
40
|
+
response = WebsocketMessage.new
|
41
|
+
|
42
|
+
if message.op_code == WebsocketMessage::OP_PING
|
43
|
+
response.fin = true
|
44
|
+
response.op_code = WebsocketMessage::OP_PONG
|
45
|
+
response.payload = "pong"
|
46
|
+
|
47
|
+
elsif message.op_code == WebsocketMessage::OP_PONG
|
48
|
+
response.fin = true
|
49
|
+
response.op_code = WebsocketMessage::OP_PING
|
50
|
+
response.payload = "ping"
|
51
|
+
|
52
|
+
elsif @delegate
|
53
|
+
@delegate.on_message(self, message.payload)
|
54
|
+
return len
|
55
|
+
|
56
|
+
else
|
57
|
+
response.fin = true
|
58
|
+
response.op_code = WebsocketMessage::OP_TEXT
|
59
|
+
response.payload = "Rakie!"
|
60
|
+
end
|
61
|
+
|
62
|
+
response_data = response.to_s
|
63
|
+
|
64
|
+
Log.debug("Rakie::Websocket response: #{response_data}")
|
65
|
+
|
66
|
+
channel.write(response_data) # Response data
|
67
|
+
|
68
|
+
elsif message.parse_status == ParseStatus::ERROR
|
69
|
+
channel.close
|
70
|
+
|
71
|
+
Log.debug("Rakie::Websocket: Illegal message")
|
72
|
+
return len
|
73
|
+
end
|
74
|
+
|
75
|
+
return len
|
76
|
+
end
|
77
|
+
|
78
|
+
def on_send(channel)
|
79
|
+
# @type [WebsocketMessage]
|
80
|
+
last_message = @send_messages.shift
|
81
|
+
|
82
|
+
if last_message
|
83
|
+
if last_message.op_code == WebsocketMessage::OP_CLOSE
|
84
|
+
Log.debug("Rakie::Websocket: send finish and close channel")
|
85
|
+
channel.close
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def on_close(channel)
|
91
|
+
if @delegate
|
92
|
+
@delegate.on_disconnect(self)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def send(message, is_binary=false)
|
97
|
+
ws_message = WebsocketMessage.new
|
98
|
+
ws_message.fin = true
|
99
|
+
ws_message.op_code = WebsocketMessage::OP_TEXT
|
100
|
+
ws_message.payload = message
|
101
|
+
|
102
|
+
if is_binary
|
103
|
+
ws_message.op_code = WebsocketMessage::OP_BIN
|
104
|
+
end
|
105
|
+
|
106
|
+
if @client_side
|
107
|
+
ws_message.mask = true
|
108
|
+
ws_message.refresh_masking
|
109
|
+
end
|
110
|
+
|
111
|
+
send_message = ws_message.to_s
|
112
|
+
|
113
|
+
Log.debug("Rakie::Websocket send: #{send_message}")
|
114
|
+
|
115
|
+
@channel.write(send_message) # Response data
|
116
|
+
end
|
117
|
+
|
118
|
+
def close
|
119
|
+
ws_message = WebsocketMessage.new
|
120
|
+
ws_message.fin = true
|
121
|
+
ws_message.op_code = WebsocketMessage::OP_CLOSE
|
122
|
+
|
123
|
+
if @client_side
|
124
|
+
ws_message.mask = true
|
125
|
+
ws_message.refresh_masking
|
126
|
+
end
|
127
|
+
|
128
|
+
ws_message.payload = "close"
|
129
|
+
|
130
|
+
send_message = ws_message.to_s
|
131
|
+
|
132
|
+
Log.debug("Rakie::Websocket send close: #{send_message}")
|
133
|
+
|
134
|
+
@channel.write(send_message) # Response data
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,286 @@
|
|
1
|
+
module Rakie
|
2
|
+
class WebsocketBasicMessage
|
3
|
+
include Proto
|
4
|
+
|
5
|
+
FLAG_FIN = 1 << 7
|
6
|
+
|
7
|
+
OP_CONTINUE = 0x0
|
8
|
+
OP_TEXT = 0x1
|
9
|
+
OP_BIN = 0x2
|
10
|
+
OP_CLOSE = 0x8
|
11
|
+
OP_PING = 0x9
|
12
|
+
OP_PONG = 0xA
|
13
|
+
|
14
|
+
FLAG_MASK = 1 << 7
|
15
|
+
|
16
|
+
PARSE_OPERATION = PARSE_BEGIN
|
17
|
+
PARSE_LEN = 1
|
18
|
+
PARSE_EXT_LEN = 2
|
19
|
+
PARSE_MASKING = 3
|
20
|
+
PARSE_PAYLOAD = 4
|
21
|
+
|
22
|
+
attr_accessor :op_code, :mask, :length, :payload
|
23
|
+
attr_writer :fin
|
24
|
+
|
25
|
+
def initialize
|
26
|
+
@fin = false
|
27
|
+
@op_code = 0x0
|
28
|
+
@mask = false
|
29
|
+
@masking = []
|
30
|
+
@length = 0
|
31
|
+
@long_ext = false
|
32
|
+
@payload = ''
|
33
|
+
end
|
34
|
+
|
35
|
+
def fin?
|
36
|
+
@fin
|
37
|
+
end
|
38
|
+
|
39
|
+
# @param [String] source
|
40
|
+
def deserialize(source)
|
41
|
+
current_state = parse_state
|
42
|
+
|
43
|
+
case current_state
|
44
|
+
when PARSE_OPERATION
|
45
|
+
return parse_source_operation(source)
|
46
|
+
|
47
|
+
when PARSE_LEN
|
48
|
+
return parse_source_len(source)
|
49
|
+
|
50
|
+
when PARSE_EXT_LEN
|
51
|
+
return parse_source_ext_len(source)
|
52
|
+
|
53
|
+
when PARSE_MASKING
|
54
|
+
return parse_source_masking(source)
|
55
|
+
|
56
|
+
when PARSE_PAYLOAD
|
57
|
+
return parse_source_payload(source)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def serialize
|
62
|
+
data = ''
|
63
|
+
|
64
|
+
data += pack_source_operation
|
65
|
+
data += pack_source_len
|
66
|
+
|
67
|
+
if @mask
|
68
|
+
data += pack_source_masking
|
69
|
+
data += pack_source_masked_payload
|
70
|
+
|
71
|
+
return data
|
72
|
+
end
|
73
|
+
|
74
|
+
data += @payload
|
75
|
+
|
76
|
+
return data
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class WebsocketMessage < WebsocketBasicMessage
|
81
|
+
# @param [String] source
|
82
|
+
def parse_source_operation(source)
|
83
|
+
offset = parse_offset
|
84
|
+
|
85
|
+
if source.length >= 1 + offset
|
86
|
+
byte = source[offset]
|
87
|
+
data = byte.unpack('C')[0]
|
88
|
+
|
89
|
+
if data & FLAG_FIN > 0
|
90
|
+
@fin = true
|
91
|
+
end
|
92
|
+
|
93
|
+
i = 3
|
94
|
+
code = 0x0
|
95
|
+
|
96
|
+
while i >= 0
|
97
|
+
code |= data & (1 << i)
|
98
|
+
i -= 1
|
99
|
+
end
|
100
|
+
|
101
|
+
@op_code = code
|
102
|
+
|
103
|
+
self.parse_state = PARSE_LEN
|
104
|
+
self.parse_offset = offset + 1
|
105
|
+
|
106
|
+
Log.debug("Rakie::WebsocketMessage parse source operation ok")
|
107
|
+
return ParseStatus::CONTINUE
|
108
|
+
end
|
109
|
+
|
110
|
+
return ParseStatus::PENDING
|
111
|
+
end
|
112
|
+
|
113
|
+
# @param [String] source
|
114
|
+
def parse_source_len(source)
|
115
|
+
offset = parse_offset
|
116
|
+
|
117
|
+
if source.length >= 1 + offset
|
118
|
+
byte = source[offset]
|
119
|
+
data = byte.unpack('C')[0]
|
120
|
+
|
121
|
+
if data & FLAG_MASK > 0
|
122
|
+
@mask = true
|
123
|
+
end
|
124
|
+
|
125
|
+
len = data & ~FLAG_MASK
|
126
|
+
|
127
|
+
Log.debug("Rakie::WebsocketMessage len: #{len}")
|
128
|
+
|
129
|
+
if len <= 125
|
130
|
+
@length = len
|
131
|
+
|
132
|
+
if @mask
|
133
|
+
self.parse_state = PARSE_MASKING
|
134
|
+
self.parse_offset = offset + 1
|
135
|
+
|
136
|
+
Log.debug("Rakie::WebsocketMessage parse source len ok")
|
137
|
+
return ParseStatus::CONTINUE
|
138
|
+
end
|
139
|
+
|
140
|
+
self.parse_state = PARSE_PAYLOAD
|
141
|
+
self.parse_offset = offset + 1
|
142
|
+
|
143
|
+
Log.debug("Rakie::WebsocketMessage parse source len ok")
|
144
|
+
return ParseStatus::CONTINUE
|
145
|
+
end
|
146
|
+
|
147
|
+
if len == 127
|
148
|
+
@long_ext = true
|
149
|
+
end
|
150
|
+
|
151
|
+
self.parse_state = PARSE_EXT_LEN
|
152
|
+
self.parse_offset = offset + 1
|
153
|
+
|
154
|
+
Log.debug("Rakie::WebsocketMessage parse source len ok")
|
155
|
+
return ParseStatus::CONTINUE
|
156
|
+
end
|
157
|
+
|
158
|
+
return ParseStatus::PENDING
|
159
|
+
end
|
160
|
+
|
161
|
+
# @param [String] source
|
162
|
+
def parse_source_ext_len(source)
|
163
|
+
offset = parse_offset
|
164
|
+
ext_len_size = 2
|
165
|
+
byte_format = 'S'
|
166
|
+
|
167
|
+
if @long_ext
|
168
|
+
ext_len_size = 8
|
169
|
+
byte_format = 'Q'
|
170
|
+
end
|
171
|
+
|
172
|
+
if source.length >= ext_len_size + offset
|
173
|
+
bytes = source[offset .. (offset + ext_len_size - 1)]
|
174
|
+
@length = bytes.unpack(byte_format + '>')[0]
|
175
|
+
|
176
|
+
if @mask
|
177
|
+
self.parse_state = PARSE_MASKING
|
178
|
+
self.parse_offset = offset + ext_len_size
|
179
|
+
|
180
|
+
Log.debug("Rakie::WebsocketMessage parse source ext len ok")
|
181
|
+
return ParseStatus::CONTINUE
|
182
|
+
end
|
183
|
+
|
184
|
+
self.parse_state = PARSE_PAYLOAD
|
185
|
+
self.parse_offset = offset + ext_len_size
|
186
|
+
|
187
|
+
Log.debug("Rakie::WebsocketMessage parse source ext len ok")
|
188
|
+
return ParseStatus::CONTINUE
|
189
|
+
end
|
190
|
+
|
191
|
+
return ParseStatus::PENDING
|
192
|
+
end
|
193
|
+
|
194
|
+
# @param [String] source
|
195
|
+
def parse_source_masking(source)
|
196
|
+
offset = parse_offset
|
197
|
+
|
198
|
+
if source.length >= 4 + offset
|
199
|
+
bytes = source[offset .. (offset + 4 - 1)]
|
200
|
+
@masking = bytes.unpack('C*')
|
201
|
+
|
202
|
+
self.parse_state = PARSE_PAYLOAD
|
203
|
+
self.parse_offset = offset + 4
|
204
|
+
|
205
|
+
Log.debug("Rakie::WebsocketMessage parse source masking ok")
|
206
|
+
return ParseStatus::CONTINUE
|
207
|
+
end
|
208
|
+
|
209
|
+
return ParseStatus::PENDING
|
210
|
+
end
|
211
|
+
|
212
|
+
# @param [String] source
|
213
|
+
def parse_source_payload(source)
|
214
|
+
offset = parse_offset
|
215
|
+
|
216
|
+
if source.length >= @length + offset
|
217
|
+
bytes = source[offset .. (offset + @length - 1)]
|
218
|
+
|
219
|
+
if @mask
|
220
|
+
bytes_list = bytes.unpack('C*')
|
221
|
+
masking = @masking
|
222
|
+
bytes_list_unmasked = bytes_list.map.with_index { |b, i| b ^ masking[i % 4] }
|
223
|
+
|
224
|
+
@payload = bytes_list_unmasked.pack('C*')
|
225
|
+
|
226
|
+
self.parse_state = PARSE_OPERATION
|
227
|
+
self.parse_offset = offset + @length
|
228
|
+
|
229
|
+
Log.debug("Rakie::WebsocketMessage parse source masked payload ok")
|
230
|
+
return ParseStatus::COMPLETE
|
231
|
+
end
|
232
|
+
|
233
|
+
@payload = bytes
|
234
|
+
|
235
|
+
self.parse_state = PARSE_OPERATION
|
236
|
+
self.parse_offset = offset + @length
|
237
|
+
|
238
|
+
Log.debug("Rakie::WebsocketMessage parse source payload ok")
|
239
|
+
return ParseStatus::COMPLETE
|
240
|
+
end
|
241
|
+
|
242
|
+
return ParseStatus::PENDING
|
243
|
+
end
|
244
|
+
|
245
|
+
def pack_source_operation
|
246
|
+
fin_bit = @fin ? 1 : 0
|
247
|
+
return [(fin_bit << 7) + @op_code].pack('C')
|
248
|
+
end
|
249
|
+
|
250
|
+
def pack_source_len
|
251
|
+
mask_bit = @mask ? 1 : 0
|
252
|
+
|
253
|
+
if @payload.length < 126
|
254
|
+
return [(mask_bit << 7) + @payload.length].pack('C')
|
255
|
+
|
256
|
+
elsif @payload.length < 65536
|
257
|
+
return [(mask_bit << 7) + 126, @payload.length].pack('CS>')
|
258
|
+
end
|
259
|
+
|
260
|
+
return [(mask_bit << 7) + 127, @payload.length].pack('CQ>')
|
261
|
+
end
|
262
|
+
|
263
|
+
def pack_source_masking
|
264
|
+
return @masking.pack('C*')
|
265
|
+
end
|
266
|
+
|
267
|
+
def pack_source_masked_payload
|
268
|
+
masking = @masking
|
269
|
+
|
270
|
+
if masking.empty?
|
271
|
+
return ''
|
272
|
+
end
|
273
|
+
|
274
|
+
bytes_list = @payload.unpack('C*')
|
275
|
+
bytes_list_masked = bytes_list.map.with_index { |b, i| b ^ masking[i % 4] }
|
276
|
+
|
277
|
+
return bytes_list_masked.pack('C*')
|
278
|
+
end
|
279
|
+
|
280
|
+
def refresh_masking
|
281
|
+
masking = []
|
282
|
+
4.times { masking << rand(1 .. 255) }
|
283
|
+
@masking = masking
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Rakie
|
2
|
+
class WebsocketServer < Websocket
|
3
|
+
# @param [Rakie::HttpServer] http_server
|
4
|
+
def initialize(delegate=nil, http_server=nil)
|
5
|
+
@delegate = delegate
|
6
|
+
|
7
|
+
if http_server == nil
|
8
|
+
http_server = HttpServer.new('127.0.0.1', 10086, self)
|
9
|
+
end
|
10
|
+
|
11
|
+
http_server.opt[:websocket_delegate] = self
|
12
|
+
@channel = http_server.channel
|
13
|
+
|
14
|
+
# @type [Array<WebsocketClient>]
|
15
|
+
@clients = {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def on_accept(channel)
|
19
|
+
ws_client = Websocket.new(@delegate, channel)
|
20
|
+
ws_client.client_side = false
|
21
|
+
|
22
|
+
channel.delegate = self
|
23
|
+
|
24
|
+
if @delegate
|
25
|
+
@delegate.on_connect(ws_client)
|
26
|
+
return
|
27
|
+
end
|
28
|
+
|
29
|
+
@clients[channel] = ws_client
|
30
|
+
Log.debug("Rakie::WebsocketServer accept client: #{ws_client}")
|
31
|
+
end
|
32
|
+
|
33
|
+
# @param [HttpRequest] request
|
34
|
+
# @param [HttpResponse] response
|
35
|
+
# @return bool
|
36
|
+
def upgrade(request, response)
|
37
|
+
if websocket_key = request.headers["sec-websocket-key"]
|
38
|
+
digest_key = Digest::SHA1.base64digest(websocket_key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11')
|
39
|
+
|
40
|
+
response.head.status = 101
|
41
|
+
response.head.message = 'Switching Protocols'
|
42
|
+
response.headers["connection"] = "upgrade"
|
43
|
+
response.headers["upgrade"] = "websocket"
|
44
|
+
response.headers["sec-websocket-accept"] = digest_key
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def on_recv(channel, data)
|
49
|
+
client = @clients[channel]
|
50
|
+
|
51
|
+
if client
|
52
|
+
client.on_recv(channel, data)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def on_send(channel)
|
57
|
+
client = @clients[channel]
|
58
|
+
|
59
|
+
if client
|
60
|
+
client.on_send(channel)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def on_close(channel)
|
65
|
+
client = @clients[channel]
|
66
|
+
|
67
|
+
if client
|
68
|
+
client.on_close(channel)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def send(message, is_binary=false); end
|
73
|
+
|
74
|
+
def close; end
|
75
|
+
|
76
|
+
def clients
|
77
|
+
@clients.values
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
require "digest"
|
83
|
+
require "base64"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rakie
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jakit Liang
|
@@ -20,9 +20,18 @@ files:
|
|
20
20
|
- lib/rakie.rb
|
21
21
|
- lib/rakie/channel.rb
|
22
22
|
- lib/rakie/event.rb
|
23
|
+
- lib/rakie/http.rb
|
24
|
+
- lib/rakie/http_proto.rb
|
25
|
+
- lib/rakie/http_server.rb
|
26
|
+
- lib/rakie/log.rb
|
27
|
+
- lib/rakie/proto.rb
|
23
28
|
- lib/rakie/simple_server.rb
|
24
29
|
- lib/rakie/tcp_channel.rb
|
25
30
|
- lib/rakie/tcp_server_channel.rb
|
31
|
+
- lib/rakie/version.rb
|
32
|
+
- lib/rakie/websocket.rb
|
33
|
+
- lib/rakie/websocket_proto.rb
|
34
|
+
- lib/rakie/websocket_server.rb
|
26
35
|
- test/test_rakie.rb
|
27
36
|
homepage: https://github.com/Jakitto/rakie
|
28
37
|
licenses:
|