Module: Sinatra::WebSocketIO

Defined in:
lib/sinatra/websocketio/client.rb,
lib/sinatra-websocketio/helpers.rb,
lib/sinatra-websocketio/options.rb,
lib/sinatra-websocketio/version.rb,
lib/sinatra/websocketio_nostart.rb,
lib/sinatra-websocketio/javascript.rb,
lib/sinatra-websocketio/application.rb,
lib/sinatra-websocketio/websocketio.rb

Defined Under Namespace

Modules: Helpers Classes: Client

Constant Summary collapse

VERSION =
"0.4.1"
@@running =
false

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.create_session(ip_addr) ⇒ Object



76
77
78
# File 'lib/sinatra-websocketio/websocketio.rb', line 76

def self.create_session(ip_addr)
  Digest::MD5.hexdigest "#{Time.now.to_i}_#{Time.now.usec}_#{ip_addr}"
end

.default_optionsObject



12
13
14
15
16
# File 'lib/sinatra-websocketio/options.rb', line 12

def self.default_options
  {
    :port => [(ENV['WS_PORT']||9000).to_i, lambda{|v| v.kind_of? Fixnum and v > 0 }]
  }
end

.javascript(*js_file_names) ⇒ Object



4
5
6
7
8
9
10
11
12
13
# File 'lib/sinatra-websocketio/javascript.rb', line 4

def self.javascript(*js_file_names)
  js_file_names = ['websocketio.js', 'event_emitter.js'] if js_file_names.empty?
  js = ''
  js_file_names.each do |i|
    File.open(File.expand_path "../js/#{i}", File.dirname(__FILE__)) do |f|
      js += f.read
    end
  end
  js
end

.optionsObject



18
19
20
21
22
23
24
25
26
# File 'lib/sinatra-websocketio/options.rb', line 18

def self.options
  @@options ||= (
                 opts = {}
                 default_options.each do |k,v|
                   opts[k] = v[0]
                 end
                 opts
                 )
end

.options=(opts) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/sinatra-websocketio/options.rb', line 28

def self.options=(opts)
  @@options = {}
  opts.each do |k,v|
    k = k.to_sym
    unless default_options.include? k
      STDERR.puts "!! Sinatra::WebSocketIO setting - \"#{k}\" is not valid key"
    else
      unless default_options[k][1].call(v)
        default = default_options[k][0]
        STDERR.puts "!! Sinatra::WebSocketIO setting - \"#{k} => #{v}\" is not valid. set default \"#{k} => #{default}\""
        @@options[k] = default
      else
        @@options[k] = v
      end
    end
  end
  default_options.each do |k, v|
    @@options[k] = v[0] unless @@options.include? k
  end
  @@options
end

.parse_handshake_params(path) ⇒ Object



80
81
82
83
84
85
86
87
# File 'lib/sinatra-websocketio/websocketio.rb', line 80

def self.parse_handshake_params(path)
  tmp = path.gsub(/^\//,'').split(/\=+/)
  params = {}
  while !tmp.empty?
    params[tmp.shift.to_sym] = tmp.shift
  end
  params
end

.push(type, data, opt = {}) ⇒ Object



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/sinatra-websocketio/websocketio.rb', line 56

def self.push(type, data, opt={})
  if opt.include? :to
    return unless self.sessions.include? opt[:to]
    s = self.sessions[opt[:to]][:websocket]
    begin
      s.send({:type => type, :data => data}.to_json)
    rescue => e
      emit :error, "websocketio push error (session:#{opt[:to]})"
    end
  else
    self.sessions.keys.each do |id|
      push type, data, :to => id
    end
  end
end

.registered(app) ⇒ Object



4
5
6
7
8
9
10
11
# File 'lib/sinatra-websocketio/application.rb', line 4

def self.registered(app)
  app.helpers Sinatra::WebSocketIO::Helpers

  app.get '/websocketio/websocketio.js' do
    content_type 'application/javascript'
    @js ||= ERB.new(Sinatra::WebSocketIO.javascript).result(binding)
  end
end

.running?Boolean

Returns:

  • (Boolean)


5
6
7
# File 'lib/sinatra-websocketio/websocketio.rb', line 5

def self.running?
  @@running
end

.sessionsObject



72
73
74
# File 'lib/sinatra-websocketio/websocketio.rb', line 72

def self.sessions
  @@sessions ||= Hash.new
end

.startObject



9
10
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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/sinatra-websocketio/websocketio.rb', line 9

def self.start
  return if running?
  @@running = true
  EM::defer do
    while !EM::reactor_running? do
      sleep 1
    end
    puts "Sinatra::WebSocketIO.start port:#{options[:port]}"
    EM::WebSocket.run :host => "0.0.0.0", :port => options[:port] do |ws|
      ws.onopen do |handshake|
        params = parse_handshake_params handshake.path
        remote_addr = Socket.unpack_sockaddr_in(ws.get_peername)[1]
        session_id = params[:session] || create_session(remote_addr)

        if self.sessions.include? session_id
          ws.send({:type => :error, :data => "invalid session_id (#{session_id})"}.to_json)
          ws.close
        else
          self.sessions[session_id] = {
            :websocket => ws,
            :remote_addr => remote_addr
          }
          ws.onclose do
            self.sessions.delete session_id
            self.emit :disconnect, session_id
          end
          ws.onmessage do |msg|
            begin
              data = ::JSON.parse msg
            rescue => e
              self.emit :error, e
            end
            self.emit data['type'], data['data'], session_id if data
          end
          ws.send({:type => :__session_id, :data => session_id}.to_json)
          self.emit :connect, session_id
        end

      end
    end

    EM::add_periodic_timer 300 do
      push :__heartbeat, {:time => Time.now}
    end
  end
end

Instance Method Details

#websocketioObject



8
9
10
# File 'lib/sinatra-websocketio/options.rb', line 8

def websocketio
  WebSocketIO.options
end

#websocketio=(options) ⇒ Object



4
5
6
# File 'lib/sinatra-websocketio/options.rb', line 4

def websocketio=(options)
  WebSocketIO.options = options
end