Class: Seahorse::Client::H2::Connection Private

Inherits:
Object
  • Object
show all
Defined in:
lib/seahorse/client/h2/connection.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

H2 Connection build on top of ‘http/2` gem

Constant Summary collapse

OPTIONS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

{
  max_concurrent_streams: 100,
  connection_timeout: 60,
  connection_read_timeout: 60,
  http_wire_trace: false,
  logger: nil,
  ssl_verify_peer: true,
  ssl_ca_bundle: nil,
  ssl_ca_directory: nil,
  ssl_ca_store: nil,
  enable_alpn: true
}
CHUNKSIZE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

chunk read size at socket

1024
SOCKET_FAMILY =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

::Socket::AF_INET

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Connection

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns a new instance of Connection.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
# File 'lib/seahorse/client/h2/connection.rb', line 33

def initialize(options = {})
  OPTIONS.each_pair do |opt_name, default_value|
    value = options[opt_name].nil? ? default_value : options[opt_name]
    instance_variable_set("@#{opt_name}", value)
  end
  @h2_client = HTTP2::Client.new(
    settings_max_concurrent_streams: @max_concurrent_streams
  )
  @logger ||= Logger.new($stdout) if @http_wire_trace
  @chunk_size = options[:read_chunk_size] || CHUNKSIZE

  @errors = []
  @status = :ready

  @mutex = Mutex.new # connection can be shared across requests
  @socket = nil
  @socket_thread = nil
end

Instance Attribute Details

#errorsObject (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



56
57
58
# File 'lib/seahorse/client/h2/connection.rb', line 56

def errors
  @errors
end

#input_signal_threadObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



58
59
60
# File 'lib/seahorse/client/h2/connection.rb', line 58

def input_signal_thread
  @input_signal_thread
end

Instance Method Details

#close!Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



134
135
136
137
138
139
140
141
142
143
# File 'lib/seahorse/client/h2/connection.rb', line 134

def close!
  @mutex.synchronize {
    self.debug_output('closing connection ...')
    if @socket
      @socket.close
      @socket = nil
    end
    @status = :closed
  }
end

#closed?Boolean

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns:

  • (Boolean)


145
146
147
# File 'lib/seahorse/client/h2/connection.rb', line 145

def closed?
  @status == :closed
end

#connect(endpoint) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/seahorse/client/h2/connection.rb', line 68

def connect(endpoint)
  @mutex.synchronize {
    if @status == :ready
      tcp, addr = _tcp_socket(endpoint)
      debug_output("opening connection to #{endpoint.host}:#{endpoint.port} ...")
      _nonblocking_connect(tcp, addr)
      debug_output('opened')

      if endpoint.scheme == 'https'
        @socket = OpenSSL::SSL::SSLSocket.new(tcp, _tls_context)
        @socket.sync_close = true
        @socket.hostname = endpoint.host

        debug_output("starting TLS for #{endpoint.host}:#{endpoint.port} ...")
        @socket.connect
        debug_output('TLS established')
      else
        @socket = tcp
      end

      _register_h2_callbacks
      @status = :active
    elsif @status == :closed
      msg = 'Async Client HTTP2 Connection is closed, you may'\
            ' use #new_connection to create a new HTTP2 Connection for this client'
      raise Http2ConnectionClosedError.new(msg)
    end
  }
end

#debug_output(msg, type = nil) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



149
150
151
152
153
154
155
156
157
158
# File 'lib/seahorse/client/h2/connection.rb', line 149

def debug_output(msg, type = nil)
  prefix =
    case type
    when :send then '-> '
    when :receive then '<- '
    else ''
    end
  return unless @logger
  _debug_entry(prefix + msg)
end

#new_streamObject

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



60
61
62
63
64
65
66
# File 'lib/seahorse/client/h2/connection.rb', line 60

def new_stream
  begin
    @h2_client.new_stream
  rescue => error
    raise Http2StreamInitializeError.new(error)
  end
end

#start(stream) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.



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
123
124
125
126
127
128
129
130
131
132
# File 'lib/seahorse/client/h2/connection.rb', line 98

def start(stream)
  @mutex.synchronize {
    return if @socket_thread
    @socket_thread = Thread.new do
      while @socket && !@socket.closed?
        begin
          data = @socket.read_nonblock(@chunk_size)
          @h2_client << data
        rescue IO::WaitReadable
          begin
            unless IO.select([@socket], nil, nil, @connection_read_timeout)
              self.debug_output('socket connection read time out')
              self.close!
            else
              # available, retry to start reading
              retry
            end
          rescue
            # error can happen when closing the socket
            # while it's waiting for read
            self.close!
          end
        rescue EOFError
          self.close!
        rescue => error
          self.debug_output(error.inspect)
          @errors << error
          self.close!
        end
      end
      @socket_thread = nil
    end
    @socket_thread.abort_on_exception = true
  }
end