Class: Goru::Routines::IO

Inherits:
Goru::Routine show all
Defined in:
lib/goru/routines/io.rb

Overview

public

Constant Summary collapse

STATUS_IO_READY =
public
:io_ready
READY_STATUSES =
[STATUS_IO_READY, Routine::STATUS_READY].freeze
READY_BRIDGE_STATUSES =
[nil, Bridge::STATUS_READY].freeze
INTENTS =
%i[r w].freeze

Constants inherited from Goru::Routine

Goru::Routine::STATUS_ERRORED, Goru::Routine::STATUS_FINISHED, Goru::Routine::STATUS_IDLE, Goru::Routine::STATUS_PAUSED, Goru::Routine::STATUS_READY

Instance Attribute Summary collapse

Attributes inherited from Goru::Routine

#debug, #error, #reactor, #state, #status

Instance Method Summary collapse

Methods inherited from Goru::Routine

#add_observer, #finished?, #pause, #remove_observer, #result, #resume, #sleep, #update

Constructor Details

#initialize(state = nil, io:, intent:, event_loop:, &block) ⇒ IO

Returns a new instance of IO.



12
13
14
15
16
17
18
19
20
# File 'lib/goru/routines/io.rb', line 12

def initialize(state = nil, io:, intent:, event_loop:, &block)
  super(state, &block)

  @io = io
  @intent = normalize_intent(intent)
  @event_loop = event_loop
  @status = :orphaned
  @monitor = nil
end

Instance Attribute Details

#intentObject

public


28
29
30
# File 'lib/goru/routines/io.rb', line 28

def intent
  @intent
end

#ioObject (readonly)

public


28
29
30
# File 'lib/goru/routines/io.rb', line 28

def io
  @io
end

#monitorObject

Returns the value of attribute monitor.



30
31
32
# File 'lib/goru/routines/io.rb', line 30

def monitor
  @monitor
end

Instance Method Details

#acceptObject

public


66
67
68
69
70
71
72
73
74
# File 'lib/goru/routines/io.rb', line 66

def accept
  @io.accept_nonblock
rescue Errno::EAGAIN
  wait
rescue Errno::ECONNRESET, Errno::EPIPE, EOFError
  handle_io_unavailable
rescue IOError
  handle_io_unavailable
end

#adoptedObject

public


34
35
36
# File 'lib/goru/routines/io.rb', line 34

def adopted
  set_status(Routine::STATUS_READY)
end

#bridge(state = nil, intent:, channel:, &block) ⇒ Object

public


124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'lib/goru/routines/io.rb', line 124

def bridge(state = nil, intent:, channel:, &block)
  raise "routine is already bridged" if @bridge

  intent = normalize_intent(intent)
  validate_intent!(intent)
  self.intent = intent

  @bridge = case intent
  when :r
    Bridges::Readable.new(routine: self, channel: channel)
  when :w
    Bridges::Writable.new(routine: self, channel: channel)
  end

  routine = case intent
  when :r
    Routines::Channels::Readable.new(state, channel: channel, &block)
  when :w
    Routines::Channels::Writable.new(state, channel: channel, &block)
  end

  @reactor.adopt_routine(routine)
  @reactor.wakeup

  routine
end

#bridgedObject

public


153
154
155
# File 'lib/goru/routines/io.rb', line 153

def bridged
  @reactor.wakeup
end

#callObject



58
59
60
61
62
# File 'lib/goru/routines/io.rb', line 58

def call
  super

  @monitor&.interests = @intent
end

#finishedObject

public


166
167
168
169
# File 'lib/goru/routines/io.rb', line 166

def finished(...)
  @io.close
  super
end

#read(bytes) ⇒ Object

public


85
86
87
88
89
90
91
92
93
# File 'lib/goru/routines/io.rb', line 85

def read(bytes)
  @io.read_nonblock(bytes)
rescue Errno::EAGAIN
  wait
rescue Errno::ECONNRESET, Errno::EPIPE, EOFError
  handle_io_unavailable
rescue IOError
  handle_io_unavailable
end

#ready?Boolean

public

Returns:

  • (Boolean)


54
55
56
# File 'lib/goru/routines/io.rb', line 54

def ready?
  READY_STATUSES.include?(@status) && READY_BRIDGE_STATUSES.include?(@bridge&.status)
end

#unbridgeObject

public


159
160
161
162
# File 'lib/goru/routines/io.rb', line 159

def unbridge
  @bridge = nil
  @reactor.wakeup
end

#waitObject



76
77
78
79
80
81
# File 'lib/goru/routines/io.rb', line 76

def wait
  set_status(:selecting)
  @reactor.register(self) unless @monitor

  throw :continue
end

#wakeupObject

public


40
41
42
43
44
45
46
47
# File 'lib/goru/routines/io.rb', line 40

def wakeup
  # Keep this io from being selected again until the underlying routine is called.
  # Interests are reset in `#call`.
  #
  @monitor&.interests = nil

  set_status(STATUS_IO_READY)
end

#write(data) ⇒ Object

public


97
98
99
100
101
102
103
104
105
# File 'lib/goru/routines/io.rb', line 97

def write(data)
  @io.write_nonblock(data)
rescue Errno::EAGAIN
  wait
rescue Errno::ECONNRESET, Errno::EPIPE, EOFError
  handle_io_unavailable
rescue IOError
  handle_io_unavailable
end