Class: Plushie::Connection

Inherits:
Object
  • Object
show all
Defined in:
lib/plushie/connection.rb,
sig/plushie/connection.rbs

Overview

Low-level protocol client for the plushie renderer.

Manages a bidirectional pipe to the renderer binary, handles wire framing, and provides thread-safe message sending. Decoded messages are pushed to a Thread::Queue or dispatched via a callback proc.

This layer is usable standalone for scripting and REPL exploration without the full Elm architecture:

conn = Plushie::Connection.spawn(format: :json)
# hello is available after spawn
puts conn.hello[:version]
conn.send_encoded(Protocol::Encode.encode_snapshot(tree, :json))
conn.close

Defined Under Namespace

Modules: _IoStreamAdapter

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#format:msgpack, :json (readonly)

Returns wire format.

Returns:

  • (:msgpack, :json)

    wire format



24
25
26
# File 'lib/plushie/connection.rb', line 24

def format
  @format
end

#helloHash? (readonly)

Returns hello handshake response from renderer.

Returns:

  • (Hash, nil)

    hello handshake response from renderer



27
28
29
# File 'lib/plushie/connection.rb', line 27

def hello
  @hello
end

Class Method Details

.attach(stdin:, stdout:, format: :msgpack, settings: {}, queue: nil, on_message: nil) ⇒ Object

Attach to existing IO streams (for :stdio transport).



58
59
60
61
62
63
64
65
66
67
68
# File 'lib/plushie/connection.rb', line 58

def self.attach(stdin:, stdout:, format: :msgpack, settings: {},
  queue: nil, on_message: nil)
  conn = new(format: format, queue: queue, on_message: on_message)
  conn.instance_variable_set(:@stdin, stdin)
  conn.instance_variable_set(:@stdout, stdout)
  stdin.binmode
  stdout.binmode
  conn.send(:perform_handshake, settings)
  conn.send(:start_reader)
  conn
end

.iostream(adapter:, format: :msgpack, settings: {}, queue: nil, on_message: nil) ⇒ Object

Create a connection backed by an iostream adapter.



91
92
93
94
95
96
# File 'lib/plushie/connection.rb', line 91

def self.iostream(adapter:, format: :msgpack, settings: {},
  queue: nil, on_message: nil)
  conn = new(format: format, queue: queue, on_message: on_message)
  conn.send(:setup_iostream, adapter, settings)
  conn
end

.spawn(format: :msgpack, binary: nil, mode: nil, max_sessions: nil, log_level: nil, settings: {}, queue: nil, on_message: nil) ⇒ Object

Spawn a renderer process and perform the hello handshake.



40
41
42
43
44
45
46
47
# File 'lib/plushie/connection.rb', line 40

def self.spawn(format: :msgpack, binary: nil, mode: nil, max_sessions: nil,
  log_level: nil, settings: {}, queue: nil, on_message: nil)
  conn = new(format: format, queue: queue, on_message: on_message)
  conn.send(:spawn_process, binary, mode, max_sessions, log_level)
  conn.send(:perform_handshake, settings)
  conn.send(:start_reader)
  conn
end

Instance Method Details

#close

This method returns an undefined value.

Close the connection.



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/plushie/connection.rb', line 165

def close
  return if @closed
  @closed = true
  stop_thread(@reader_thread, timeout: 1)
  @reader_thread = nil
  if @iostream_adapter
    @iostream_adapter.stop if @iostream_adapter.respond_to?(:stop)
  else
    begin
      @stdin&.close
    rescue
      nil
    end
    begin
      @stdout&.close
    rescue
      nil
    end
    begin
      @process_thread&.value
    rescue
      nil
    end
  end
end

#closed?Boolean

Whether the connection is closed.

Returns:

  • (Boolean)


192
193
194
# File 'lib/plushie/connection.rb', line 192

def closed?
  @closed
end

#receive_data(data)

This method returns an undefined value.

Called by iostream adapter when data arrives.

Parameters:

  • data (String)


126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/plushie/connection.rb', line 126

def receive_data(data)
  return if @closed

  msg = Protocol::Decode.decode(data, @format)
  decoded = Protocol::Decode.dispatch_message(msg)

  if !@hello && decoded.is_a?(Hash) && decoded[:type] == :hello
    @hello = decoded
    @handshake_queue&.push(decoded)
  elsif decoded
    dispatch_message(decoded)
  end
end

#send_encoded(data)

This method returns an undefined value.

Send pre-encoded wire bytes to the renderer.

Parameters:

  • data (String)


101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/plushie/connection.rb', line 101

def send_encoded(data)
  @write_mutex.synchronize do
    if @iostream_adapter
      @iostream_adapter.send_data(data)
    else
      case @format
      when :msgpack
        @stdin.write([data.bytesize].pack("N"))
        @stdin.write(data)
      when :json
        @stdin.write(data)
      end
      @stdin.flush
    end
  end
rescue IOError, Errno::EPIPE => e
  @closed = true
  dispatch_message({type: :connection_error, error: e})
end

#send_message(msg)

This method returns an undefined value.

Encode a hash and send it.

Parameters:

  • msg (Hash[Symbol, untyped])


152
153
154
# File 'lib/plushie/connection.rb', line 152

def send_message(msg)
  send_encoded(Protocol::Encode.encode(msg, @format))
end

#send_message_for_session(msg, session_id)

This method returns an undefined value.

Send a message with a specific session ID.

Parameters:

  • msg (Hash[Symbol, untyped])
  • session_id (String)


160
161
162
# File 'lib/plushie/connection.rb', line 160

def send_message_for_session(msg, session_id)
  send_message(msg.merge(session: session_id))
end

#transport_closed(reason)

This method returns an undefined value.

Called by iostream adapter when the transport closes.

Parameters:

  • reason (Symbol, String)


143
144
145
146
147
# File 'lib/plushie/connection.rb', line 143

def transport_closed(reason)
  return if @closed
  @closed = true
  dispatch_message({type: :connection_closed, reason: reason})
end