#!/usr/bin/env ruby 

# HTTP Push Server
#
#Copyright (c) 2006 Alexander MacCaw

#Permission is hereby granted, free of charge, to any person obtaining
#a copy of this software and associated documentation files (the
#"Software"), to deal in the Software without restriction, including
#without limitation the rights to use, copy, modify, merge, publish,
#distribute, sublicense, and/or sell copies of the Software, and to
#permit persons to whom the Software is furnished to do so, subject to
#the following conditions:

#The above copyright notice and this permission notice shall be
#included in all copies or substantial portions of the Software.

#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
#EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
#MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
#LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
#OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
#WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


require "socket"
require "thread"
require "logger"
require "base64"
require File.dirname(__FILE__) + '/../vendor/plugins/flash_socket/lib/flash_socket'


FLASH_SOCKET_DEFAULT_HOSTNAME = FlashSocket.host
FLASH_SOCKET_DEFAULT_PORT = FlashSocket.port
FLASH_SOCKET_ALLOWED_IP = FlashSocket.allowed_ip

      class Client
        def initialize(sock)
          @socket = sock
          @queue = Queue.new
          Thread.new do
            while @queue do
              d = @queue.pop
              break if d == '!'
              @socket.puts d
            end
          end
        end
        def puts(d)
          @queue.push d
        end
        def gets
          @socket.gets
        end
        def peeraddr
          @socket.peeraddr
        end
        def close
          @socket.close
          @queue.push '!'
        end
      end

      class PushServer
	 
	 def initialize
	   @logger = Logger.new("log/application.log", 5, 10*1024)
	   log("Setting up Server")

       	   @server = TCPServer.new(FLASH_SOCKET_DEFAULT_HOSTNAME, FLASH_SOCKET_DEFAULT_PORT)

       	   addr = @server.addr 
           addr.shift 
	   log("Server is on...\nIP:\t#{addr[2]}\nPort:\t#{addr[0]}\nComputer Name:\t#{addr[1]}\nAllowed IP for rails:\t#{FLASH_SOCKET_ALLOWED_IP}\n")

	   @clients = []
	   @clientsMutex = Mutex.new
	 end
	 
	 def serve
	   while (socket = @server.accept)
	     client = Client.new(socket)
	     add_client(client)
	     listen(client)
	   end
	 end
	 
	 def add_client(client)
	   @clientsMutex.synchronize do
	     @clients << client
	   end
	   peeraddr = client.peeraddr
	   if client.peeraddr[3] == FLASH_SOCKET_ALLOWED_IP
	   log("Rails connected: \tIP:\t #{peeraddr[3]} \tName:\t #{peeraddr[2]}")
	   else
	   log("Client added: \tIP:\t #{peeraddr[3]} \tName:\t #{peeraddr[2]}")
	   end
	 end
	 
	 def remove_client(client)
	   @clientsMutex.synchronize do
	     @clients.delete(client)
	   end
	    if client.peeraddr[3] == FLASH_SOCKET_ALLOWED_IP
	      log("Rails removed")
	    else
	      log("Client removed")
	    end
	 end
	 
	 def listen(client)
	  @listen_thread = Thread.new do
	     while line = client.gets
	        break if /^QUIT/ =~ line
	        break unless client.peeraddr[3] == FLASH_SOCKET_ALLOWED_IP
	        broadcast(client, line)
	     end
	     remove_client(client)
	     client.close
	   end
	 end
	   
	 def broadcast(client, line)
	   @clientsMutex.synchronize do
	     @clients.each do | c |
	       c.puts(Base64.encode64(line) + "\0\n") if c != client
	     end
	   end
	   log "Rails says: " + line
	 end
	 
	 
	def log(text)
	  puts text
	  @logger.info(text)
	end
	
	def shutdown
	 @server.close
	 @clients = nil
	end
	
     end
     
     ps = PushServer.new
     trap("INT") { ps.shutdown }
     ps.serve
     
