rakie 0.0.2 → 0.0.8

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 95d75f7ea14d2462c94b21bd025f17e5150075e295dd1dc9f927efb08826c424
4
- data.tar.gz: 2642f719d6ae1427e99efc89b3d841fe7c7471f5cfd2da0597ad4df89d347b0e
3
+ metadata.gz: 81b73eacd5a896ae3c13192543965d353a0b2dcd1e1ae021664e91793d130d77
4
+ data.tar.gz: bf30ef52373d98df118064c99aaaf7465e6ac8f684d0d49bea01f7d9c6f1a5ff
5
5
  SHA512:
6
- metadata.gz: ae10ff4d934dac0f08a066d2809930132b736e4cb4bda7f7cf25f30cc48f7554b4b474e8ee7cbb7fcd57b7b4e75157d9a592ff9a8351f3d9fbee431b4006e944
7
- data.tar.gz: 287525054ef601031d860c7a8b75b1985e91d7430cee7b489b7fb726c06cbe15223c3ebd63cad3fbdf590793d3cb343dbfc0a6890cba89a9cbf6b632541ab6a2
6
+ metadata.gz: 8a2152503ca81745b8ed0cc467826cd8efd4d8006b8760ed102500f80c3bc88bf946196d03bc3242f87e7db512152147781384be05d891d51fa4aca4928428d2
7
+ data.tar.gz: 29934b5f3ecf636d047c04b00a83e45ddf54a581476f65b23cfe106f231c9cf399536d42f5b2b194ed96c747c41639999be7009e4521481ae989727b4902e5eb
data/lib/rakie.rb CHANGED
@@ -1,10 +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"
18
+ require "rakie/http_server"
19
+ require "rakie/websocket"
20
+ require "rakie/websocket_server"
9
21
  require "rakie/tcp_channel"
10
22
  require "rakie/tcp_server_channel"
23
+ require "rakie/log"
24
+ require "rakie/version"
data/lib/rakie/channel.rb CHANGED
@@ -2,10 +2,13 @@ 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
8
10
  @write_buffer = String.new
11
+ @write_task = []
9
12
  @delegate = delegate
10
13
  Event.push(io, self, Event::READ_EVENT)
11
14
  end
@@ -13,25 +16,28 @@ module Rakie
13
16
  def on_read(io)
14
17
  begin
15
18
  loop do
16
- @read_buffer << io.read_nonblock(4096)
19
+ @read_buffer << io.read_nonblock(DEFAULT_BUFFER_SIZE)
17
20
  end
18
21
 
19
22
  rescue IO::EAGAINWaitReadable
20
- puts("Channel read finished")
23
+ Log.debug("Channel read pending")
21
24
 
22
- rescue
25
+ rescue IO::EWOULDBLOCKWaitReadable
26
+ Log.debug("Channel read pending")
27
+
28
+ rescue Exception => e
23
29
  # Process the last message on exception
24
30
  if @delegate != nil
25
31
  @delegate.on_recv(self, @read_buffer)
26
32
  @read_buffer = String.new # Reset buffer
27
33
  end
28
34
 
29
- puts("Channel error #{io}")
35
+ Log.debug("Channel error #{io}: #{e}")
30
36
  return Event::HANDLE_FAILED
31
37
  end
32
38
 
33
- puts("Channel has delegate?: #{@delegate}")
34
39
  if @delegate != nil
40
+ Log.debug("Channel handle on_recv")
35
41
  len = @delegate.on_recv(self, @read_buffer)
36
42
 
37
43
  if len > @read_buffer.length
@@ -39,40 +45,77 @@ module Rakie
39
45
  end
40
46
 
41
47
  @read_buffer = @read_buffer[len .. -1]
42
- puts("Channel handle on_recv")
43
48
  end
44
49
 
45
50
  return Event::HANDLE_CONTINUED
46
51
  end
47
52
 
53
+ def handle_write(len)
54
+ task = @write_task[0]
55
+
56
+ while len > 0
57
+ if len < task
58
+ @write_task[0] = task - len
59
+ end
60
+
61
+ len -= task
62
+ @write_task.shift
63
+
64
+ if @delegate != nil
65
+ @delegate.on_send(self)
66
+ Log.debug("Channel handle on_send")
67
+ end
68
+ end
69
+ end
70
+
48
71
  def on_write(io)
72
+ len = 0
73
+ offset = 0
74
+
49
75
  begin
50
76
  while @write_buffer.length > 0
51
77
  len = io.write_nonblock(@write_buffer)
78
+ offset += len
52
79
  @write_buffer = @write_buffer[len .. -1]
53
80
  end
54
81
 
55
- puts("Channel write finished")
82
+ Log.debug("Channel write finished")
56
83
 
57
84
  rescue IO::EAGAINWaitWritable
58
- puts("Channel write continue")
85
+ self.handle_write(offset)
86
+
87
+ Log.debug("Channel write pending")
88
+ return Event::HANDLE_CONTINUED
89
+
90
+ rescue IO::EWOULDBLOCKWaitWritable
91
+ self.handle_write(offset)
92
+
93
+ Log.debug("Channel write pending")
59
94
  return Event::HANDLE_CONTINUED
60
95
 
61
96
  rescue
62
- puts("Channel close #{io}")
97
+ Log.debug("Channel close #{io}")
63
98
  return Event::HANDLE_FAILED
64
99
  end
65
100
 
101
+ self.handle_write(offset)
102
+
66
103
  return Event::HANDLE_FINISHED
67
104
  end
68
105
 
69
- def on_close(io)
106
+ def on_detach(io)
70
107
  begin
71
108
  io.close
72
109
 
110
+ if @delegate
111
+ @delegate.on_close(self)
112
+ end
113
+
73
114
  rescue
74
- puts("Channel is already closed")
115
+ Log.debug("Channel is already closed")
75
116
  end
117
+
118
+ Log.debug("Channel close ok")
76
119
  end
77
120
 
78
121
  def read(size)
@@ -96,7 +139,9 @@ module Rakie
96
139
  end
97
140
 
98
141
  @write_buffer << data
99
- Event.modify(@io, self, Event::READ_EVENT | Event::WRITE_EVENT)
142
+ @write_task << data.length
143
+
144
+ Event.modify(@io, self, (Event::READ_EVENT | Event::WRITE_EVENT))
100
145
 
101
146
  return 0
102
147
  end
data/lib/rakie/event.rb CHANGED
@@ -9,6 +9,10 @@ module Rakie
9
9
  HANDLE_CONTINUED = 0
10
10
  HANDLE_FINISHED = 1
11
11
 
12
+ OPERATION_ADD = 0
13
+ OPERATION_MODIFY = 1
14
+ OPERATION_DELETE = 2
15
+
12
16
  def initialize
13
17
  @wait_ios = []
14
18
  @lock = Mutex.new
@@ -24,36 +28,39 @@ module Rakie
24
28
 
25
29
  def process_signal(io)
26
30
  signal = io.read(1)
27
- puts("Event handling #{signal}")
28
31
 
29
- if signal == 'a'
30
- new_io, new_handler, new_event = @wait_ios.shift
32
+ if signal == 'q'
33
+ return 1
34
+ end
35
+
36
+ operation, new_io, new_handler, new_event = @wait_ios.shift
37
+ if new_io.closed?
38
+ return 0
39
+ end
40
+
41
+ Log.debug("Event handling #{signal} with #{new_io.fileno} to #{new_event}")
42
+
43
+ if operation == OPERATION_ADD
31
44
  @ios[new_io] = new_event
32
45
  @handlers[new_io] = new_handler
33
- puts("Event add all #{new_io} to #{new_event}")
46
+ Log.debug("Event add all #{new_io.fileno} to #{new_event}")
34
47
 
35
- elsif signal == 'd'
36
- new_io, = @wait_ios.shift
48
+ elsif operation == OPERATION_DELETE
37
49
  handler = @handlers[new_io]
38
50
 
39
51
  if handler != nil
40
- handler.on_close(new_io)
41
- puts("Event close #{new_io}")
52
+ Log.debug("Event close #{new_io}")
53
+ handler.on_detach(new_io)
42
54
  end
43
55
 
44
56
  @ios.delete(new_io)
45
57
  @handlers.delete(new_io)
58
+ Log.debug("Event remove all #{new_io}")
46
59
 
47
- puts("Event remove all #{new_io}")
48
-
49
- elsif signal == 'm'
50
- new_io, new_handler, new_event = @wait_ios.shift
60
+ elsif operation == OPERATION_MODIFY
51
61
  @ios[new_io] = new_event
52
62
  @handlers[new_io] = new_handler
53
- puts("Event modify all #{new_io} to #{new_event}")
54
-
55
- elsif signal == 'q'
56
- return 1
63
+ Log.debug("Event modify all #{new_io.fileno} to #{new_event}")
57
64
  end
58
65
 
59
66
  return 0
@@ -61,9 +68,18 @@ module Rakie
61
68
 
62
69
  def run_loop
63
70
  loop do
71
+ # p @ios
72
+ # begin
73
+ # read_ios = @ios.select {|k, v| v & READ_EVENT > 0}
74
+ # write_ios = @ios.select {|k, v| v & WRITE_EVENT > 0}
75
+ # rescue Exception => e
76
+ # p @ios
77
+ # end
78
+
64
79
  read_ios = @ios.select {|k, v| v & READ_EVENT > 0}
65
80
  write_ios = @ios.select {|k, v| v & WRITE_EVENT > 0}
66
81
 
82
+ # Log.debug("Event selecting ...")
67
83
  read_ready, write_ready = IO.select(read_ios.keys, write_ios.keys, [], 5)
68
84
 
69
85
  if read_ready != nil
@@ -89,16 +105,16 @@ module Rakie
89
105
  result = handler.on_read(io)
90
106
 
91
107
  if result == HANDLE_FINISHED
92
- @ios[io] = @ios[io] & ~READ_EVENT
93
- puts("Event remove read #{io}")
108
+ @ios[io] &= ~READ_EVENT
109
+ Log.debug("Event remove read #{io}")
94
110
 
95
111
  elsif result == HANDLE_FAILED
96
- handler.on_close(io)
97
- puts("Event close #{io}")
112
+ handler.on_detach(io)
113
+ Log.debug("Event close #{io}")
98
114
 
99
115
  @ios.delete(io)
100
116
  @handlers.delete(io)
101
- puts("Event remove all #{io}")
117
+ Log.debug("Event remove all #{io}")
102
118
  end
103
119
  end
104
120
  end
@@ -114,16 +130,16 @@ module Rakie
114
130
  result = handler.on_write(io)
115
131
 
116
132
  if result == HANDLE_FINISHED
117
- @ios[io] = @ios[io] & ~WRITE_EVENT
118
- puts("Event remove write #{io}")
133
+ @ios[io] &= ~WRITE_EVENT
134
+ Log.debug("Event remove write #{io}")
119
135
 
120
136
  elsif result == HANDLE_FAILED
121
- handler.on_close(io)
122
- puts("Event close #{io}")
137
+ handler.on_detach(io)
138
+ Log.debug("Event close #{io}")
123
139
 
124
140
  @ios.delete(io)
125
141
  @handlers.delete(io)
126
- puts("Event remove all #{io}")
142
+ Log.debug("Event remove all #{io}")
127
143
  end
128
144
  end
129
145
  end
@@ -132,39 +148,58 @@ module Rakie
132
148
 
133
149
  def push(io, handler, event)
134
150
  @lock.lock
135
- @wait_ios.push([io, handler, event])
151
+ @wait_ios.push([OPERATION_ADD, io, handler, event])
136
152
  @signal_out.write('a')
137
153
  @lock.unlock
138
154
  end
139
155
 
140
156
  def delete(io)
141
157
  @lock.lock
142
- @wait_ios.push([io, nil, nil])
143
- @signal_out.write('d')
158
+ @wait_ios.push([OPERATION_DELETE, io, nil, nil])
159
+ @signal_out.write('a')
144
160
  @lock.unlock
145
161
  end
146
162
 
147
163
  def modify(io, handler, event)
148
164
  @lock.lock
149
- @wait_ios.push([io, handler, event])
150
- @signal_out.write('m')
165
+ @wait_ios.push([OPERATION_MODIFY, io, handler, event])
166
+ @signal_out.write('a')
151
167
  @lock.unlock
152
168
  end
153
169
 
154
170
  def self.instance
155
- @instance ||= Event.new
171
+ @instance ||= Array.new(self.concurrent) { |i| Event.new }
156
172
  end
157
173
 
158
174
  def self.push(io, listener, type)
159
- self.instance.push(io, listener, type)
175
+ i = io.fileno % self.concurrent
176
+ inst = self.instance[i]
177
+ inst.push(io, listener, type)
178
+ # instance.push(io, listener, type)
160
179
  end
161
180
 
162
181
  def self.delete(io)
163
- self.instance.delete(io)
182
+ i = io.fileno % self.concurrent
183
+ inst = self.instance[i]
184
+ inst.delete(io)
185
+ # self.instance.delete(io)
164
186
  end
165
187
 
166
188
  def self.modify(io, listener, type)
167
- self.instance.modify(io, listener, type)
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
168
203
  end
169
204
  end
170
205
  end
data/lib/rakie/http.rb ADDED
@@ -0,0 +1,5 @@
1
+ module Rakie
2
+ class Http
3
+
4
+ end
5
+ 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