Module: Scarpe::WVRelayUtil

Included in:
Scarpe::Webview::ContainedService, Scarpe::Webview::RelayDisplayService
Defined in:
lib/scarpe/wv/webview_relay_util.rb

Overview

WVRelayUtil defines the datagram format for the sockets that connect a parent Shoes application with a child display server.

The class including this module should also include Shoes::Log so that it can be used.

Instance Method Summary collapse

Instance Method Details

#event_loop_for(t = 1.5) ⇒ Object

Loop for up to t seconds, reading data and waiting.

Parameters:

  • t (Float) (defaults to: 1.5)

    the number of seconds to loop for



127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/scarpe/wv/webview_relay_util.rb', line 127

def event_loop_for(t = 1.5)
  t_start = Time.now
  delay_time = t

  while Time.now - t_start < delay_time
    if ready_to_read?(0.1)
      respond_to_datagram
    else
      sleep 0.1
    end
  end
end

#ready_to_read?(timeout = 0.0) ⇒ Boolean

Checks whether the internal socket is ready to be read from. If timeout is greater than 0, this will block for up to that long.

Parameters:

  • timeout (Float) (defaults to: 0.0)

    the longest to wait for more input to read

Returns:

  • (Boolean)

    whether the socket has data ready for reading



17
18
19
20
21
22
23
24
25
26
27
28
# File 'lib/scarpe/wv/webview_relay_util.rb', line 17

def ready_to_read?(timeout = 0.0)
  r, _, e = IO.select [@from], [], [@from, @to].uniq, timeout

  # On timeout, select returns nil instead of arrays.
  return if r.nil?

  unless e.empty?
    raise Scarpe::ConnectionError, "#{@i_am}: Got error on connection(s) from IO.select! Dying!"
  end

  !r.empty?
end

#receive_datagramString

Read data from the internal socket. Read until a whole datagram has been received and then return it.

Returns:

  • (String)

    the received datagram



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/scarpe/wv/webview_relay_util.rb', line 56

def receive_datagram
  @readbuf ||= String.new.encode(Encoding::BINARY)
  to_read = nil

  loop do
    # Have we read a packet length already, sitting in @readbuf?
    a_idx = @readbuf.index("a")
    if a_idx
      to_read = @readbuf[0..a_idx].to_i
      @readbuf = @readbuf[(a_idx + 1)..-1]
      break
    end

    # If not, read more bytes
    new_bytes = @from.read(10)
    if new_bytes.nil?
      # This is perfectly normal, if the connection closed
      raise Scarpe::AppShutdownError, "Got an unexpected EOF reading datagram! " +
        "Did the #{@i_am == :child ? "parent" : "child"} process die?"
    end
    @readbuf << new_bytes
  end

  loop do
    if @readbuf.bytesize >= to_read
      out = @readbuf.byteslice(0, to_read)
      @readbuf = @readbuf.byteslice(to_read, -1)
      return out
    end

    new_bytes = @from.read(to_read - @readbuf.bytesize)
    @readbuf << new_bytes
  end
rescue
  raise Scarpe::AppShutdownError, "Got exception #{$!.class} when receiving datagram... #{$!.inspect}"
end

#respond_to_datagramObject

Read a datagram from the internal buffer and then dispatch it to the appropriate handler.



95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/scarpe/wv/webview_relay_util.rb', line 95

def respond_to_datagram
  message = receive_datagram
  m_data = JSON.parse(message)

  if m_data["type"] == "event"
    kwargs_hash = {}
    m_data["kwargs"].each { |k, v| kwargs_hash[k.to_sym] = v }
    send_shoes_event(
      *m_data["args"],
      event_name: m_data["kwargs"]["event_name"],
      target: m_data["kwargs"]["event_target"],
      **kwargs_hash,
    )
  elsif m_data["type"] == "create"
    raise Scarpe::InvalidOperationError, "Parent process should never receive :create datagram!" if @i_am == :parent

    @wv_display.create_display_drawable_for(m_data["class_name"], m_data["id"], m_data["properties"])
  elsif m_data["type"] == "destroy"
    if @i_am == :parent
      @shutdown = true
    else
      @log.info("Shutting down...")
      exit 0
    end
  else
    @log.error("Unrecognized datagram type:event: #{m_data.inspect}!")
  end
end

#send_datagram(contents) ⇒ void

This method returns an undefined value.

Send bytes on the internal socket to the opposite side.

Parameters:

  • contents (String)

    data to send



34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/scarpe/wv/webview_relay_util.rb', line 34

def send_datagram(contents)
  str_data = JSON.dump contents
  dgram_str = (str_data.length.to_s + "a" + str_data).encode(Encoding::BINARY)
  to_write = dgram_str.bytesize
  written = 0

  until written == to_write
    count = @to.write(dgram_str.byteslice(written..-1))
    if count.nil? || count == 0
      raise Scarpe::DatagramSendError, "Something was wrong in send_datagram! Write returned #{count.inspect}!"
    end

    written += count
  end

  nil
end