Class: Bridge::Connection

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

Overview

:nodoc: all

Defined Under Namespace

Classes: SockBuffer

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(bridge) ⇒ Connection

Returns a new instance of Connection.



11
12
13
14
15
16
17
18
19
20
21
22
23
# File 'lib/connection.rb', line 11

def initialize bridge
  # Set associated bridge object
  @bridge = bridge

  @options = bridge.options
  
  # Preconnect buffer
  @sock_buffer = SockBuffer.new
  @sock = @sock_buffer
  
  # Connection configuration
  @interval = 0.4
end

Instance Attribute Details

#client_idObject

Returns the value of attribute client_id.



9
10
11
# File 'lib/connection.rb', line 9

def client_id
  @client_id
end

#connectedObject

Returns the value of attribute connected.



9
10
11
# File 'lib/connection.rb', line 9

def connected
  @connected
end

#optionsObject

Returns the value of attribute options.



9
10
11
# File 'lib/connection.rb', line 9

def options
  @options
end

#sockObject

Returns the value of attribute sock.



9
10
11
# File 'lib/connection.rb', line 9

def sock
  @sock
end

Instance Method Details

#establish_connectionObject



60
61
62
63
# File 'lib/connection.rb', line 60

def establish_connection
  Util.info "Starting TCP connection #{@options[:host]}, #{@options[:port]}"
  EventMachine::connect(@options[:host], @options[:port], Tcp, self)
end

#oncloseObject



96
97
98
99
100
101
102
103
# File 'lib/connection.rb', line 96

def onclose
  Util.warn 'Connection closed'
  # Restore preconnect buffer as socket connection
  @sock = @sock_buffer
  if @options[:reconnect]
    reconnect
  end
end

#onmessage(data, sock) ⇒ Object



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/connection.rb', line 65

def onmessage data, sock
  # Parse for client id and secret
  m = /^(\w+)\|(\w+)$/.match data[:data]
  if not m
    # Handle message normally if not a correct CONNECT response
    process_message data
  else
    Util.info "client_id received, #{m[1]}"
    @client_id = m[1]
    @secret = m[2]
    # Reset reconnect interval
    @interval = 0.4
    # Send preconnect queued messages
    @sock_buffer.process_queue sock, @client_id
    # Set connection socket to connected socket
    @sock = sock
    Util.info('Handshake complete')
    # Trigger ready callback
    if not @bridge.is_ready
      @bridge.is_ready = true
      @bridge.emit 'ready'
    end
  end
end

#onopen(sock) ⇒ Object



90
91
92
93
94
# File 'lib/connection.rb', line 90

def onopen sock
  Util.info 'Beginning handshake' 
  msg = Util.stringify(:command => :CONNECT, :data => {:session => [@client_id || nil, @secret || nil], :api_key => @options[:api_key]})
  sock.send msg
end

#process_message(message) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/connection.rb', line 105

def process_message message
  begin
    Util.info "Received #{message[:data]}"
    message = Util.parse(message[:data])
  rescue Exception => e
    Util.error "Message parsing failed"
  end
  # Convert serialized ref objects to callable references
  Serializer.unserialize(@bridge, message['args'])
  # Extract RPC destination address
  destination = message['destination']
  if !destination
    Util.warn "No destination in message #{message}"
    return
  end
  if message['source']
    @bridge.context = Client.new(@bridge, message['source'])
  end
  @bridge.execute message['destination']['ref'], message['args']
end

#reconnectObject



49
50
51
52
53
54
55
56
57
58
# File 'lib/connection.rb', line 49

def reconnect
  Util.info "Attempting to reconnect"
  if @interval < 32768
    EventMachine::Timer.new(@interval) do
      establish_connection
      # Grow timeout for next reconnect attempt
      @interval *= 2
    end
  end
end

#redirectorObject

Contact redirector for host and ports



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/connection.rb', line 26

def redirector
  # Support for redirector.
  uri = URI(@options[:redirector])
  conn = EventMachine::Protocols::HttpClient2.connect(:host => uri.host, :port => uri.port, :ssl => @options[:secure])
  req = conn.get({:uri => "/redirect/#{@options[:api_key]}"})
  req.callback do |obj|
    begin
      obj = JSON::parse obj.content
    rescue Exception => e
      Util.error "Unable to parse redirector response #{obj.content}"
      return
    end
    if obj.has_key?('data') and obj['data'].has_key?('bridge_host') and obj['data'].has_key?('bridge_port')
      obj = obj['data']
      @options[:host] = obj['bridge_host']
      @options[:port] = obj['bridge_port']
      establish_connection
    else
      Util.error "Could not find host and port in JSON body"
    end
  end
end

#send_command(command, data) ⇒ Object



126
127
128
129
130
131
# File 'lib/connection.rb', line 126

def send_command command, data
  data.delete :callback if data.key? :callback and data[:callback].nil?
  msg = Util.stringify :command => command, :data => data
  Util.info "Sending #{msg}"
  @sock.send msg
end

#startObject



133
134
135
136
137
138
139
140
# File 'lib/connection.rb', line 133

def start 
  if !@options.has_key? :host or !@options.has_key? :port
    redirector
  else
    # Host and port are specified
    establish_connection
  end
end