Class: ScaleRb::WsClient

Inherits:
Object
  • Object
show all
Includes:
ClientShare
Defined in:
lib/scale_rb/client/ws_client.rb,
lib/scale_rb/client/ws_client.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ClientShare

#get_metadata, #get_storage

Constructor Details

#initialize(connection) ⇒ WsClient

Returns a new instance of WsClient.



58
59
60
61
62
63
# File 'lib/scale_rb/client/ws_client.rb', line 58

def initialize(connection)
  @connection = connection
  @response_handler = ResponseHandler.new
  @subscription_handler = SubscriptionHandler.new
  @request_id = 1
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/scale_rb/client/ws_client.rb', line 69

def method_missing(method, *args)
  method = method.to_s

  # why not check 'rpc_methods', because there is no @supported_methods when initializing
  if method != 'rpc_methods' && !@supported_methods.include?(method)
    raise "Method `#{method}` is not supported. It should be in [#{@supported_methods.join(', ')}]."
  end

  if method.include?('unsubscribe')
    unsubscribe(method, args[0])
  elsif method.include?('subscribe')
    raise 'A subscribe method needs a block' unless block_given?

    subscribe(method, args) do |notification|
      yield notification[:params][:result]
    end
  else
    request(method, args)
  end
end

Instance Attribute Details

#supported_methodsObject

Returns the value of attribute supported_methods.



56
57
58
# File 'lib/scale_rb/client/ws_client.rb', line 56

def supported_methods
  @supported_methods
end

Class Method Details

.start(url) ⇒ Object

Parameters:

  • url (string)


11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/scale_rb/client/ws_client.rb', line 11

def start(url)
  Sync do
    endpoint = Async::HTTP::Endpoint.parse(url, alpn_protocols: Async::HTTP::Protocol::HTTP11.names)

    Async::WebSocket::Client.connect(endpoint) do |connection|
      client = WsClient.new(connection)

      # `recv_task` does not raise errors (subclass of StandardError), so it will not be stopped by any errors.
      recv_task = Async do
        while (message = client.read_message)
          data = parse_message(message)
          next if data.nil?

          ScaleRb.logger.debug "←— #{data}"
          Async do
            client.handle_response(data)
          end
        end
      end

      client.supported_methods = client.rpc_methods[:methods]
      yield client

      recv_task.wait
    ensure
      recv_task&.stop
    end
  end
end

Instance Method Details

#handle_response(response) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
# File 'lib/scale_rb/client/ws_client.rb', line 107

def handle_response(response)
  if response.key?(:id)
    @response_handler.handle(response)
  elsif response.key?(:method)
    @subscription_handler.handle(response)
  else
    ScaleRb.logger.info "Received an unknown response: #{response}"
  end
rescue StandardError => e
  Console::Event::Failure.for(e).emit(self, 'Handle response failed!')
end

#read_messageObject



119
120
121
122
123
124
125
126
127
# File 'lib/scale_rb/client/ws_client.rb', line 119

def read_message
  loop do
    return @connection.read
  rescue StandardError => e
    Console::Event::Failure.for(e).emit(self, 'Read message from connection failed!')
    sleep 1
    retry
  end
end

#respond_to_missing?(method) ⇒ Boolean

Returns:

  • (Boolean)


65
66
67
# File 'lib/scale_rb/client/ws_client.rb', line 65

def respond_to_missing?(method, *)
  @supported_methods.include?(method.to_s)
end

#subscribe(method, params = [], &block) ⇒ Object



90
91
92
93
94
95
96
97
# File 'lib/scale_rb/client/ws_client.rb', line 90

def subscribe(method, params = [], &block)
  return unless method.include?('subscribe')
  return if method.include?('unsubscribe')

  subscription_id = request(method, params)
  @subscription_handler.subscribe(subscription_id, block)
  subscription_id
end

#unsubscribe(method, subscription_id) ⇒ Object



99
100
101
102
103
104
105
# File 'lib/scale_rb/client/ws_client.rb', line 99

def unsubscribe(method, subscription_id)
  return unless method.include?('unsubscribe')

  return unless @subscription_handler.unsubscribe(subscription_id)

  request(method, [subscription_id])
end