Class: Async::WebSocket::Client

Inherits:
Object
  • Object
show all
Defined in:
lib/async/websocket/client.rb

Overview

This is a basic synchronous websocket client:

Constant Summary collapse

HTTP_VERSION =
'HTTP/1.0'.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(endpoint, headers: [], protocols: [], version: 13, key: SecureRandom.base64(16)) ⇒ Client

Returns a new instance of Client.

Parameters:

  • protocols (Hash) (defaults to: [])

    a customizable set of options

Options Hash (protocols:):

  • a (Array)

    list of supported sub-protocols to negotiate with the server.



43
44
45
46
47
48
49
50
51
# File 'lib/async/websocket/client.rb', line 43

def initialize(endpoint, headers: [], protocols: [], version: 13, key: SecureRandom.base64(16))
	@endpoint = endpoint
	@version = version
	@headers = headers
	
	@protocols = protocols
	
	@key = key
end

Instance Attribute Details

#headersObject (readonly)

Returns the value of attribute headers.



53
54
55
# File 'lib/async/websocket/client.rb', line 53

def headers
  @headers
end

Class Method Details

.open(endpoint, **options, &block) ⇒ Object



33
34
35
36
37
38
39
40
# File 'lib/async/websocket/client.rb', line 33

def self.open(endpoint, **options, &block)
	# endpoint = Async::HTTP::URLEndpoint.parse(url)
	client = self.new(endpoint, **options)
	
	return client unless block_given?
	
	client.get(endpoint.path, &block)
end

Instance Method Details

#call(method, path) ⇒ Object

Raises:



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/async/websocket/client.rb', line 88

def call(method, path)
	client = connect
	client.upgrade!("websocket")
	
	client.write_request(@endpoint.authority, method, @endpoint.path, HTTP_VERSION, self.request_headers)
	stream = client.write_upgrade_body
	
	version, status, reason, headers, body = client.read_response(method)
	
	raise ProtocolError, "Expected status 101, got #{status}!" unless status == 101
	
	accept_digest = headers['sec-websocket-accept'].first
	if accept_digest.nil? or accept_digest != ::Protocol::WebSocket.accept_digest(@key)
		raise ProtocolError, "Invalid accept header, got #{accept_digest.inspect}!"
	end
	
	connection = make_connection(stream, headers)
		
	return connection unless block_given?
	
	begin
		yield connection
	ensure
		connection.close
	end
end

#connectObject



55
56
57
58
59
# File 'lib/async/websocket/client.rb', line 55

def connect
	peer = @endpoint.connect
	
	return ::Protocol::HTTP1::Connection.new(IO::Stream.new(peer), false)
end

#get(path = '/', &block) ⇒ Object



74
75
76
# File 'lib/async/websocket/client.rb', line 74

def get(path = '/', &block)
	self.call('GET', path, &block)
end

#make_connection(stream, headers) ⇒ Object



80
81
82
83
84
85
86
# File 'lib/async/websocket/client.rb', line 80

def make_connection(stream, headers)
	protocol = headers['sec-websocket-protocol']&.first
	
	framer = Protocol::WebSocket::Framer.new(stream)
	
	return Connection.new(framer, protocol)
end

#request_headersObject



61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/async/websocket/client.rb', line 61

def request_headers
	headers = [
		['sec-websocket-key', @key],
		['sec-websocket-version', @version]
	] + @headers.to_a
	
	if @protocols.any?
		headers << ['sec-websocket-protocol', @protocols.join(',')]
	end
	
	return headers
end