lightio 0.4.2 → 0.4.3

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
- SHA1:
3
- metadata.gz: d60e525147d0be04ceecef1b5d5707dbaeeba6d1
4
- data.tar.gz: 69c611c348c2837484857e850834e6bc93fc6c44
2
+ SHA256:
3
+ metadata.gz: 0461dd68b60dfa05c34fabdcd916ef074de8e634634174fc5253dbc5083d221a
4
+ data.tar.gz: 0715bf64fe6b6150d629136b621eec9d6a79c72dc7110e19082dd4e59b14a0a9
5
5
  SHA512:
6
- metadata.gz: a53025d4e89dcfab86d8c41af53b0a8ac078d86d9a220549a364638be22be4da133c303ce3e738a910b6a9844907a5c4ee506f27fa041728930770ea0ac1ea61
7
- data.tar.gz: 60e88d7aed7cf946368cc1f2aa6786d644c00d30fa9f2c0855b5cb9fb1c41d4837e0e98b52beb85fbaa761af9c39beaa92dda8cfcbdea6afb584b0859bcc831f
6
+ metadata.gz: 8c7796bdbcb7cc253979813fe394fe65dec6eab3ee53384042a267fa5cf2fef316a946b732e0adc42f1c343c53c4602f7149617d7626066984156ea8fc581d0b
7
+ data.tar.gz: 71e6b9f3b63d6e236ea6fb5b0629f6634fe9d60d459d63f78fd5b7406027ca5858add3e0f0d502278938db0d6e2b4d8e930171850a9fa7305b695b6fc5de3ce5
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lightio (0.4.2)
4
+ lightio (0.4.3)
5
5
  nio4r (~> 2.2)
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -5,6 +5,7 @@
5
5
  [![Build Status](https://travis-ci.org/socketry/lightio.svg?branch=master)](https://travis-ci.org/socketry/lightio)
6
6
  [![Coverage Status](https://coveralls.io/repos/github/socketry/lightio/badge.svg?branch=master)](https://coveralls.io/github/socketry/lightio?branch=master)
7
7
  [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/jjyr/lightio/blob/master/LICENSE.txt)
8
+ [![Gitter](https://badges.gitter.im/join.svg)](https://gitter.im/lightio-dev/Lobby)
8
9
 
9
10
  LightIO provide green thread to ruby. Like Golang's goroutine, or Crystal's fiber. In LightIO it called beam.
10
11
 
@@ -12,6 +12,7 @@ module LightIO::Core
12
12
  @value = nil
13
13
  @ioloop = IOloop.current
14
14
  @state = :init
15
+ @light_fiber = nil
15
16
  end
16
17
 
17
18
  def done?
@@ -98,6 +98,7 @@ module LightIO::Library
98
98
  else
99
99
  mock_obj = allocate
100
100
  mock_obj.instance_variable_set(:@obj, obj)
101
+ mock_obj.__send__(:call_lightio_initialize)
101
102
  mock_obj
102
103
  end
103
104
  end
@@ -106,9 +107,15 @@ module LightIO::Library
106
107
  def initialize(*args)
107
108
  obj = self.class.send(:call_method_from_ancestors, :mock_klass).send(:origin_new, *args)
108
109
  @obj = obj
110
+ call_lightio_initialize
111
+ @obj
109
112
  end
110
113
 
111
114
  private
115
+ def call_lightio_initialize
116
+ __send__(:lightio_initialize) if respond_to?(:lightio_initialize, true)
117
+ end
118
+
112
119
  def light_io_raw_obj
113
120
  @obj
114
121
  end
@@ -1,3 +1,5 @@
1
+ require 'io/wait'
2
+
1
3
  module LightIO::Library
2
4
  class IO
3
5
  include Base
@@ -19,8 +21,25 @@ module LightIO::Library
19
21
  end
20
22
  end
21
23
 
24
+ def lightio_initialize
25
+ @readbuf = StringIO.new
26
+ @readbuf.set_encoding(@obj.external_encoding) if @obj.respond_to?(:external_encoding)
27
+ @eof = nil
28
+ @seek = 0
29
+ end
30
+
22
31
  def wait(timeout = nil, mode = :read)
23
- io_watcher.wait(timeout, mode) && self
32
+ # avoid wait if can immediately return
33
+ wait_result = if RUBY_VERSION < '2.4'
34
+ if mode == :read
35
+ @obj.wait_readable(0)
36
+ elsif mode == :write
37
+ @obj.wait_writable(0)
38
+ end
39
+ else
40
+ @obj.wait(0, mode)
41
+ end
42
+ (wait_result || io_watcher.wait(timeout, mode)) && self
24
43
  end
25
44
 
26
45
  def wait_readable(timeout = nil)
@@ -31,30 +50,21 @@ module LightIO::Library
31
50
  wait(timeout, :write) && self
32
51
  end
33
52
 
34
- def read(length=nil, outbuf=nil)
35
- raise ArgumentError, "negative length #{length} given" if length && length < 0
36
- (outbuf ||= "").clear
37
- loop do
38
- readlen = length.nil? ? 4096 : length - outbuf.size
39
- if (data = wait_nonblock(:read_nonblock, readlen))
40
- outbuf << data
41
- if length == outbuf.size
42
- return outbuf
43
- end
44
- else
45
- return outbuf.empty? && length ? nil : outbuf
46
- end
53
+ def read(length = nil, outbuf = nil)
54
+ while !fill_read_buf && (length.nil? || length > @readbuf.length - @readbuf.pos)
55
+ wait_readable
47
56
  end
57
+ @readbuf.read(length, outbuf)
48
58
  end
49
59
 
50
- def readpartial(maxlen, outbuf=nil)
51
- (outbuf ||= "").clear
52
- if (data = wait_nonblock(:read_nonblock, maxlen))
53
- outbuf << data
54
- else
55
- raise EOFError, 'end of file reached'
60
+ def readpartial(maxlen, outbuf = nil)
61
+ raise ArgumentError, "negative length #{maxlen} given" if maxlen < 0
62
+ fill_read_buf
63
+ while @readbuf.eof? && !io_eof?
64
+ wait_readable
65
+ fill_read_buf
56
66
  end
57
- outbuf
67
+ @readbuf.readpartial(maxlen, outbuf)
58
68
  end
59
69
 
60
70
  def getbyte
@@ -62,8 +72,13 @@ module LightIO::Library
62
72
  end
63
73
 
64
74
  def getc
65
- wait_readable
66
- @obj.getc
75
+ fill_read_buf
76
+ until (c = @readbuf.getc)
77
+ return nil if nonblock_eof?
78
+ wait_readable
79
+ fill_read_buf
80
+ end
81
+ c
67
82
  end
68
83
 
69
84
  def readline(*args)
@@ -73,11 +88,10 @@ module LightIO::Library
73
88
  end
74
89
 
75
90
  def readlines(*args)
76
- result = []
77
- until eof?
78
- result << readline(*args)
91
+ until fill_read_buf
92
+ wait_readable
79
93
  end
80
- result
94
+ @readbuf.readlines(*args)
81
95
  end
82
96
 
83
97
  def readchar
@@ -93,8 +107,13 @@ module LightIO::Library
93
107
  end
94
108
 
95
109
  def eof
96
- wait_readable
97
- @obj.eof
110
+ # until eof have a value
111
+ fill_read_buf
112
+ while @readbuf.eof? && @eof.nil?
113
+ wait_readable
114
+ fill_read_buf
115
+ end
116
+ nonblock_eof?
98
117
  end
99
118
 
100
119
  alias eof? eof
@@ -103,19 +122,17 @@ module LightIO::Library
103
122
  raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 0..2)" if args.size > 2
104
123
  sep = $/
105
124
  if args[0].is_a?(Numeric)
106
- limit = args.shift
125
+ limit = args[0]
107
126
  else
108
- sep = args.shift if args.size > 0
109
- limit = args.shift if args.first.is_a?(Numeric)
127
+ sep = args[0] if args.size > 0
128
+ limit = args[1] if args[1].is_a?(Numeric)
110
129
  end
111
- s = ''
112
- while (c = getbyte)
113
- s << c
114
- break if limit && s.size == limit
115
- break if c == sep
130
+ until fill_read_buf
131
+ break if limit && limit <= @readbuf.length
132
+ break if sep && @readbuf.string.index(sep)
133
+ wait_readable
116
134
  end
117
- s = nil if s.empty?
118
- $_ = s
135
+ @readbuf.gets(*args)
119
136
  end
120
137
 
121
138
  def print(*obj)
@@ -135,11 +152,79 @@ module LightIO::Library
135
152
  end
136
153
  end
137
154
 
155
+ def flush
156
+ @obj.flush
157
+ self
158
+ end
159
+
138
160
  def close(*args)
139
161
  # close watcher before io closed
140
162
  io_watcher.close
141
163
  @obj.close
142
164
  end
165
+
166
+ private
167
+
168
+ def nonblock_eof?
169
+ @readbuf.eof? && io_eof?
170
+ end
171
+
172
+ def io_eof?
173
+ @eof
174
+ end
175
+
176
+ BUF_CHUNK_SIZE = 1024 * 16
177
+
178
+ def fill_read_buf
179
+ return true if @eof
180
+ while (data = @obj.read_nonblock(BUF_CHUNK_SIZE, exception: false))
181
+ case data
182
+ when :wait_readable, :wait_writable
183
+ # set eof to unknown(nil)
184
+ @eof = nil
185
+ return nil
186
+ else
187
+ # set eof to false
188
+ @eof = false if @eof.nil?
189
+ @readbuf.string << data
190
+ end
191
+ end
192
+ # set eof to true
193
+ @eof = true
194
+ end
195
+ end
196
+
197
+ def set_encoding(*args)
198
+ @readbuf.set_encoding(*args)
199
+ super(*args)
200
+ end
201
+
202
+ def lineno
203
+ @readbuf.lineno
204
+ end
205
+
206
+ def lineno= no
207
+ @readbuf.lineno = no
208
+ end
209
+
210
+ def rewind
211
+ # clear buf if seek offset is not zero
212
+ unless @seek.zero?
213
+ @seek = 0
214
+ @readbuf.string.clear
215
+ end
216
+ @readbuf.rewind
217
+ end
218
+
219
+ def seek(*args)
220
+ @readbuf.string.clear
221
+ @seek = args[0]
222
+ @obj.seek(*args)
223
+ end
224
+
225
+ def binmode
226
+ @obj.binmode
227
+ self
143
228
  end
144
229
 
145
230
  prepend IOMethods
@@ -153,6 +153,7 @@ module LightIO::Library
153
153
  @obj = socket
154
154
  wait_nonblock(:connect_nonblock, remote_address)
155
155
  @obj
156
+ lightio_initialize
156
157
  end
157
158
 
158
159
  private
@@ -167,6 +168,7 @@ module LightIO::Library
167
168
 
168
169
  def initialize(*args)
169
170
  @obj = ::TCPServer.send(:origin_new, *args)
171
+ lightio_initialize
170
172
  end
171
173
 
172
174
  def accept
@@ -1,3 +1,3 @@
1
1
  module LightIO
2
- VERSION = "0.4.2"
2
+ VERSION = "0.4.3"
3
3
  end
@@ -21,16 +21,19 @@ module LightIO::Watchers
21
21
  @io = io
22
22
  @ioloop = LightIO::Core::IOloop.current
23
23
  @waiting = false
24
- ObjectSpace.define_finalizer(self, self.class.finalizer(@monitor))
25
24
  @error = nil
26
25
  # maintain socket status, see https://github.com/socketry/lightio/issues/1
27
26
  @readiness = nil
27
+ @monitor = nil
28
28
  end
29
29
 
30
30
  # NIO::Monitor
31
31
  def monitor(interests=:rw)
32
32
  @monitor ||= begin
33
- @ioloop.add_io_wait(@io, interests) {callback_on_waiting}
33
+ raise @error if @error
34
+ monitor = @ioloop.add_io_wait(@io, interests) {callback_on_waiting}
35
+ ObjectSpace.define_finalizer(self, self.class.finalizer(monitor))
36
+ monitor
34
37
  end
35
38
  end
36
39
 
@@ -41,7 +44,13 @@ module LightIO::Watchers
41
44
  end
42
45
 
43
46
  extend Forwardable
44
- def_delegators :monitor, :interests, :interests=, :closed?
47
+ def_delegators :monitor, :interests, :interests=
48
+
49
+ def closed?
50
+ # check @monitor exists, avoid unnecessary monitor created
51
+ return true unless @monitor
52
+ monitor.closed?
53
+ end
45
54
 
46
55
  # this method return previous IO.select status
47
56
  # should avoid to directly use
@@ -90,9 +99,9 @@ module LightIO::Watchers
90
99
  end
91
100
 
92
101
  def close
102
+ set_close_error
93
103
  return if closed?
94
104
  monitor.close
95
- @error = IOError.new('closed stream')
96
105
  callback_on_waiting
97
106
  end
98
107
 
@@ -107,6 +116,10 @@ module LightIO::Watchers
107
116
  end
108
117
 
109
118
  private
119
+ def set_close_error
120
+ @error ||= IOError.new('closed stream')
121
+ end
122
+
110
123
  def check_monitor(mode)
111
124
  case mode
112
125
  when :read
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lightio
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jiang Jinyang
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-02-15 00:00:00.000000000 Z
11
+ date: 2018-02-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nio4r
@@ -153,7 +153,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
153
  version: '0'
154
154
  requirements: []
155
155
  rubyforge_project:
156
- rubygems_version: 2.6.14
156
+ rubygems_version: 2.7.3
157
157
  signing_key:
158
158
  specification_version: 4
159
159
  summary: LightIO is a ruby networking library, that combines ruby fiber and fast IO