class Object

Public Instance Methods

http_server(options) click to toggle source
# File lib/mqtt-sn-http.rb, line 7
def http_server options
  
  prev_t={}
  ports=['127.0.0.1']
  if Socket.method_defined? :getifaddrs
    ports=Socket.getifaddrs.map { |i| i.addr.ip_address if i.addr.ipv4? }.compact
    puts "Starting HTTP services at port #{options[:http_port]}, server IPs: #{ports}"
  else
    puts "Starting HTTP services at port #{options[:http_port]}."
  end
  if File.directory? './http'
    $http_dir="http/"
  else
    $http_dir = File.join( Gem.loaded_specs['mqtt-sn-ruby'].full_gem_path, 'http/')
  end

  Thread.new(options[:http_port],options[:app_name]) do |http_port,http_app|
    server = TCPServer.new("0.0.0.0",http_port)
    @http_sessions={}
    http_session_counter=1
    loop do
      Thread.start(server.accept) do |client|
        begin
          request = client.gets.split " "
          status="200 OK"
          type="text/html"
          req=request[1]
          req="/#{http_app}.html" if req=="/" or req=="/index.htm" or req=="/index.html"
          req,argss=req.split "\?"
          #puts "req: #{req}, agss:#{argss}"
          args={}
          if argss
            argss.split("&").each do |a|
              if a
                k,v=URI.decode(a).force_encoding("UTF-8").split "="
                args[k]=v
              end
            end
          end
          #puts "req: #{req}, args:#{args}"
          if req[/\.html$/] and File.file?(fn="#{$http_dir}haml#{req.gsub('.html','.haml')}")
            contents = File.read(fn)
            response=Haml::Engine.new(contents).render
          elsif req[/\.js$/] and File.file?(fn="#{$http_dir}coffee#{req.gsub('.js','.coffee')}")
            type="application/javascript"
            contents = File.read(fn)
            begin
              response=CoffeeScript.compile contents
            rescue => e
              response="Coffee Compile error: #{e}"
            end
          elsif req[/^\/(.+)\.json$/] and File.file?(fn="#{$http_dir}json#{req.gsub('.json','.rb')}")
            req[/\/(.+).json$/] 
            act=$1
            #puts "act:#{act} args:#{args}"
            t=File.mtime(fn)
            if not prev_t[fn] or prev_t[fn]<t
              begin
                load_ok=load fn
                prev_t[fn]=t
              rescue Exception => e
                puts "**** RELOAD #{fn} failed:  #{e}"
                pp e.backtrace
                response=[{act: :error, msg:"Error loading JSON",alert: "Load error #{e} in #{fn}"}].to_json
                type="text/json"
                status="404 Not Found"
              end
            end
            if type!="text/event-stream" and status=="200 OK"
              begin
                type,response=eval "json_#{act} req,args,0,0"  #event handlers get called with zero session => init :)
              rescue => e
                puts "**** AJAX EXEC #{fn} failed:  #{e}"
                pp e.backtrace
                response=[{act: :error, msg:"Error executing JSON",alert: "Syntax error '#{e}' in '#{fn}'"}].to_json
                type="text/json"
              end
              response=response.to_json
             end
          elsif req[/\.css$/] and File.file?(fnc="#{$http_dir}css#{req}")
            type="text/css"
            contents = File.read(fnc)
            response=contents
          else
            status="404 Not Found"
            response="Not Found: #{request[1]}"
          end
          client.print "HTTP/1.1 #{status}\r\n" +
                 "Content-Type: #{type}\r\n"
          if type!="text/event-stream"
            client.print "Content-Length: #{response.bytesize}\r\n"
            client.print "Connection: close\r\n"
            client.print "\r\n"
            client.print response 
          else
            client.print "Expires: -1\r\n"
            client.print "\r\n"
            begin
              my_session=client.peeraddr[1]
              if not @http_sessions[my_session]
                #puts "**************** new port #{my_session}"
                @http_sessions[my_session]={client_port:client.peeraddr[1],client_ip:client.peeraddr[2] , log_position:0 }
              end
              my_event=0
              loop do
                begin
                  type,response=eval "json_#{act} request,args,my_session,my_event"
                  my_event+=1
                rescue => e
                  puts "**** AJAX EXEC #{fn} failed:  #{e}"
                  puts "#{e.backtrace[0..2]}"
                  pp e.backtrace
                  response=[{act: :error, msg:"Error executing JSON",alert: "Syntax error '#{e}' in '#{fn}'"}].to_json
                end 
                if not response or response==[] or response=={}
                else
                  client.print  "retry: 1000\n"
                  client.print  "data: #{response.to_json}\n\n"
                end
                sleep 1
                break if my_event>100
              end
            rescue => e
              puts "stream #{client} died #{e}"
              pp e.backtrace
            end

          end
          client.close
        rescue Exception =>e
          puts "http thread died #{e}"
          pp e.backtrace
          client.print "Error #{e}"
          client.close
        end
      end
    end
  end
end