rakie 0.0.2 → 0.0.8

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
  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