#!/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