Class: Bayeux

Inherits:
Sinatra::Base
  • Object
show all
Defined in:
lib/bayeux.rb

Overview

A Sinatra application that handles PUTs and POSTs on the /cometd URL, implementing the COMET protocol.

Defined Under Namespace

Classes: Client

Constant Summary collapse

VERSION =

The Gem version of this implementation

"0.6.2"

Instance Method Summary collapse

Instance Method Details

#channelsObject

A Hash of channels by channel name. Each channel is an Array of subscribed clients



77
78
79
80
# File 'lib/bayeux.rb', line 77

def channels
  # Sinatra dup's this object, so we have to use class variables
  @@channels ||= Hash.new {|h, k| h[k] = [] }
end

#clientsObject

A Hash of all clients by clientId



83
84
85
# File 'lib/bayeux.rb', line 83

def clients
  @@clients ||= {}
end

#deliver(message) ⇒ Object

Handle a request from a client. Normally over-ridden in the subclass to add server behaviour.



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/bayeux.rb', line 109

def deliver(message)
  id = message['id']
  clientId = message['clientId']
  channel_name = message['channel']

  response =
    case channel_name
    when '/meta/handshake'      # Client says hello, greet them
      clientId = next_client_id
      clients[clientId] = Client.new(clientId)
      trace "Client #{clientId} offers a handshake from #{request.ip}"
      handshake message

    when '/meta/subscribe'      # Client wants to subscribe to a channel:
      subscribe message

    when '/meta/unsubscribe'    # Client wants to unsubscribe from a channel:
      unsubscribe message

    # This is the long-polling request.
    when '/meta/connect'
      connect message

    when '/meta/disconnect'
      disconnect message

    # Other meta channels are disallowed
    when %r{/meta/(.*)}
      trace "Client #{clientId} tried to send a message to #{channel_name}"
      { :successful => false }

    # Service channels default to no-op. Service messages are never broadcast.
    when %r{/service/(.*)}
      trace "Client #{clientId} sent a private message to #{channel_name}"
      { :successful => true }

    else
      puts "Unknown channel in request: "+message.inspect
      pass  # 404
    end

  # Set the standard parameters for all response messages
  if response
    response[:channel] = channel_name
    response[:clientId] = clientId
    response[:id] = id
    [response]
  else
    []
  end
end

#next_client_idObject

ClientIds should be strong random numbers containing at least 128 bits of entropy. These aren’t!



88
89
90
91
92
93
94
# File 'lib/bayeux.rb', line 88

def next_client_id
  begin
    id = (rand*1_000_000_000).to_i
  end until !clients[id]
  trace "New client recieves ID #{id}"
  id
end

#publish(message) ⇒ Object

Send a message (a Hash) to a channel. The message must have the channel name under the key :channel or “channel”



98
99
100
101
102
103
104
105
106
# File 'lib/bayeux.rb', line 98

def publish message
  channel = message['channel'] || message[:channel]
  clients = channels[channel]
  trace "publishing to #{channel} with #{clients.size} subscribers: #{message.inspect}"
  clients.each do | client|
    client.queue << message
    client.channel.push true    # Wake up the subscribed client
  end
end

#respond(messages) ⇒ Object

Send an asynchronous JSON or JSONP response to an async_sinatra GET or POST



162
163
164
165
166
167
168
169
170
171
172
# File 'lib/bayeux.rb', line 162

def respond messages
  if jsonp = params['jsonp']
    trace "responding jsonp=#{messages.to_json}"
    headers({'Content-Type' => 'text/javascript'})
    body "#{jsonp}(#{messages.to_json});\n"
  else
    trace "responding #{messages.to_json}"
    headers({'Content-Type' => 'application/json'})
    body messages.to_json
  end
end

#trace(s) ⇒ Object

Trace to stdout if the :tracing setting is enabled



70
71
72
73
74
# File 'lib/bayeux.rb', line 70

def trace s
  if settings.tracing
    puts s
  end
end