module Sinatra::CometIO

Constants

VERSION

Public Class Methods

create_session(ip_addr) click to toggle source
# File lib/sinatra-cometio/cometio.rb, line 53
def self.create_session(ip_addr)
  Digest::MD5.hexdigest "#{Time.now.to_i}_#{Time.now.usec}_#{ip_addr}"
end
default_options() click to toggle source
# File lib/sinatra-cometio/options.rb, line 12
def self.default_options
  {
    :timeout => [120, lambda{|v| v.kind_of? Fixnum and v >= 20 }],
    :post_interval => [1, lambda{|v| [Fixnum, Float].include? v.class and v >= 1 }],
    :allow_crossdomain => [false, lambda{|v| [true, false].include? v }]
  }
end
gc() click to toggle source
# File lib/sinatra-cometio/cometio.rb, line 14
def self.gc
  self.sessions.each do |id, s|
    next unless s[:last] and s[:last] < Time.now-CometIO.options[:timeout]*2-10
    self.sessions.delete id rescue next
    self.emit :disconnect, id
  end
end
javascript(*js_file_names) click to toggle source
# File lib/sinatra-cometio/javascript.rb, line 4
def self.javascript(*js_file_names)
  js_file_names = ['cometio.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
options() click to toggle source
# File lib/sinatra-cometio/options.rb, line 20
def self.options
  @@options ||= (
                 opts = {}
                 default_options.each do |k,v|
                   opts[k] = v[0]
                 end
                 opts
                 )
end
options=(opts) click to toggle source
# File lib/sinatra-cometio/options.rb, line 30
def self.options=(opts)
  @@options = {}
  opts.each do |k,v|
    k = k.to_sym
    unless default_options.include? k
      STDERR.puts "!! Sinatra::CometIO setting - \"#{k}\" is not valid key"
    else
      unless default_options[k][1].call(v)
        default = default_options[k][0]
        STDERR.puts "!! Sinatra::CometIO 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
push(type, data, opt={}) click to toggle source
# File lib/sinatra-cometio/cometio.rb, line 29
def self.push(type, data, opt={})
  if opt.include? :to
    return unless self.sessions.include? opt[:to]
    s = self.sessions[opt[:to]]
    if s[:queue].empty? and s[:stream] != nil
      begin
        s[:stream].write([{:type => type, :data => data}].to_json)
        s[:stream].flush
        s[:stream].close
      rescue
        s[:stream].close
        s[:queue].push :type => type, :data => data
      end
      s[:stream] = nil
    else
      s[:queue].push :type => type, :data => data
    end
    return
  end
  self.sessions.keys.each do |id|
    push type, data, :to => id
  end
end
registered(app) click to toggle source
# File lib/sinatra-cometio/application.rb, line 4
def self.registered(app)
  app.helpers Sinatra::Streaming
  app.helpers Sinatra::CometIO::Helpers

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

  app.get '/cometio/io' do
    response["Access-Control-Allow-Origin"] = "*" if CometIO.options[:allow_crossdomain]
    stream :keep_open do |s|
      session = params[:session].to_s.empty? ? CometIO.create_session(request.ip) : params[:session]
      CometIO.sessions[session][:remote_addr] = request.env['REMOTE_ADDR']
      CometIO.sessions[session][:stream] = s
      CometIO.sessions[session][:last] = Time.now
      CometIO.emit :connect, session if params[:session].to_s.empty?

      unless CometIO.sessions[session][:queue].empty?
        begin
          s.write CometIO.sessions[session][:queue].to_json
          s.flush
          s.close
        rescue
          s.close
        end
        CometIO.sessions[session][:queue] = []
      end

      EM::add_timer CometIO.options[:timeout] do
        begin
          s.write([{:type => :__heartbeat, :data => {:time => Time.now.to_i}}].to_json)
          s.flush
          s.close
        rescue
          s.close
        end
      end
    end
  end

  app.post '/cometio/io' do
    response["Access-Control-Allow-Origin"] = "*" if CometIO.options[:allow_crossdomain]
    data = ::JSON.parse params[:json] rescue halt 500, 'JSON parse error'
    from = data['session']
    halt 400, 'no session' if !from or from.empty?
    events = data['events']
    halt 400, 'no data' unless [Hash, Array].include? events.class
    events = events.keys.sort.map{|i| events[i] } if events.kind_of? Hash
    EM::defer do
      events.each do |e|
        next if !e['type'] or e['type'].empty?
        CometIO.emit e['type'], e['data'], from
      end
    end
    stream :keep_open do |s|
      begin
        s.write({:session => from, :success => true}.to_json)
        s.flush
        s.close
      rescue
        s.close
      end
    end
  end

end
sessions() click to toggle source
# File lib/sinatra-cometio/cometio.rb, line 4
def self.sessions
  @@sessions ||= Hash.new{|h,session_id|
    h[session_id] = {
      :queue => [{:type => :__session_id, :data => session_id}],
      :stream => nil,
      :last => nil
    }
  }
end

Public Instance Methods

cometio() click to toggle source
# File lib/sinatra-cometio/options.rb, line 8
def cometio
  CometIO.options
end
cometio=(options) click to toggle source
# File lib/sinatra-cometio/options.rb, line 4
def cometio=(options)
  CometIO.options = options
end