Class: Mfp::Server::Conn

Inherits:
Object
  • Object
show all
Defined in:
lib/mfp/server/conn.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(server, id, peer_socket, call_sign, settings) ⇒ Conn

Returns a new instance of Conn.



8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# File 'lib/mfp/server/conn.rb', line 8

def initialize(server, id, peer_socket, call_sign, settings)
  @logger = settings.logger
  @server = server
  @sock = peer_socket
  @call_sign = call_sign
  @max_streams = settings.max_streams
  @max_payload = settings.max_payload
  @id = id
  @first_frame_timeout = settings.first_frame_timeout_secs

  @to_write = Async::Queue.new
  @to_read = Async::Queue.new
  @compression = Compressor.new(:identity)
  @ping_handler = PingHandler.new(
    idle_timeout: settings.idle_timeout_secs,
    ping_timeout: settings.ping_timeout_secs,
  )

  @application = nil
  @hostname = nil
  @closed = false
end

Instance Attribute Details

#applicationObject (readonly)

Returns the value of attribute application.



6
7
8
# File 'lib/mfp/server/conn.rb', line 6

def application
  @application
end

#closedObject (readonly)

Returns the value of attribute closed.



6
7
8
# File 'lib/mfp/server/conn.rb', line 6

def closed
  @closed
end

#hostnameObject (readonly)

Returns the value of attribute hostname.



6
7
8
# File 'lib/mfp/server/conn.rb', line 6

def hostname
  @hostname
end

#idObject (readonly)

Returns the value of attribute id.



6
7
8
# File 'lib/mfp/server/conn.rb', line 6

def id
  @id
end

#max_payloadObject (readonly)

Returns the value of attribute max_payload.



6
7
8
# File 'lib/mfp/server/conn.rb', line 6

def max_payload
  @max_payload
end

#max_streamsObject (readonly)

Returns the value of attribute max_streams.



6
7
8
# File 'lib/mfp/server/conn.rb', line 6

def max_streams
  @max_streams
end

Instance Method Details

#closeObject



61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/mfp/server/conn.rb', line 61

def close
  return if @closed

  @logger.debug("Closing connection")

  @closed = true

  @ping_handler&.stop
  @sock&.close
  @server.disconnect(self)
  @to_read.close
  @task&.cancel
end

#recvObject



75
# File 'lib/mfp/server/conn.rb', line 75

def recv = @to_read.dequeue

#send_control(stream_id, msg, flags: 0) ⇒ Object

Raises:

  • (ArgumentError)


89
90
91
92
93
94
95
96
97
98
99
# File 'lib/mfp/server/conn.rb', line 89

def send_control(stream_id, msg, flags: 0)
  raise ArgumentError, "msg must be a String or nil" unless msg.nil? || msg.is_a?(String)

  send_conn_frame(Proto::Frame.new(
    stream_id:,
    kind: Proto::MessageKind::CONTROL,
    flags:,
    length: msg&.bytesize || 0,
    payload: msg,
  ))
end

#send_error(stream_id, terminal:, code:, debug:) ⇒ Object



101
102
103
104
105
# File 'lib/mfp/server/conn.rb', line 101

def send_error(stream_id, terminal:, code:, debug:)
  debug = debug.to_s unless debug.nil?
  msg = Proto::Error.new(code, terminal:, debug:)
  send_conn_frame(msg.encode(stream_id))
end

#send_stream(stream_id, msg, flags: 0) ⇒ Object

Raises:

  • (ArgumentError)


77
78
79
80
81
82
83
84
85
86
87
# File 'lib/mfp/server/conn.rb', line 77

def send_stream(stream_id, msg, flags: 0)
  raise ArgumentError, "msg must be a String or nil" unless msg.nil? || msg.is_a?(String)

  send_conn_frame(Proto::Frame.new(
    stream_id:,
    kind: Proto::MessageKind::STREAM,
    flags:,
    length: msg&.bytesize || 0,
    payload: msg,
  ))
end

#start(task) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/mfp/server/conn.rb', line 31

def start(task)
  @task = task.async do |t|
    @write_task = t.async { handle_writes }
    begin
      status, err = t.with_timeout(@first_frame_timeout) { perform_handshake }
    rescue Async::TimeoutError => e
      @logger.error("Timeout waiting for full handshake", e)
      status = :failed
      err = e
    rescue StandardError => e
      @logger.error("Failed performing handshake", e)
      status = :failed
      err = e
    end

    if status == :failed
      @logger.error("Failed completing handshake", err)
      next
    end

    @server.connect(self)
    @ping_handler.start(t)
    t.async { handle_pings }

    run_loop
  ensure
    close
  end
end