# Copyright (c) The PyAMF Project.
# See LICENSE.txt for details.
 
"""
Example socket server using Twisted.
 
@see: U{Documentation for this example<http://pyamf.org/tutorials/actionscript/socket.html>}
 
@since: 0.1
"""
 
 
try:
    import twisted
except ImportError:
    print "This examples requires the Twisted framework. Download it from http://twistedmatrix.com"
    raise SystemExit
 
from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor
 
from datetime import datetime
import pyamf
 
 
class TimerProtocol(Protocol):
    interval = 1.0 # interval in seconds to send the time
    encoding = pyamf.AMF3
    timeout = 300 
 
    def __init__(self):
        self.started = False
        self.encoder = pyamf.get_encoder(self.encoding)
        self.stream = self.encoder.stream
 
    def connectionLost(self, reason):
        Protocol.connectionLost(self, reason)
 
        self.factory.number_of_connections -= 1
 
    def connectionMade(self):
        if self.factory.number_of_connections >= self.factory.max_connections:
            self.transport.write('Too many connections, try again later')
            self.transport.loseConnection()
 
            return
 
        self.factory.number_of_connections += 1
        self.timeout_deferred = reactor.callLater(TimerProtocol.timeout, self.transport.loseConnection)
 
    def dataReceived(self, data):
        data = data.strip()
        if data == 'start':
            # start sending a date object that contains the current time
            if not self.started:
                self.start()
        elif data == 'stop':
            self.stop()
 
        if self.timeout_deferred:
            self.timeout_deferred.cancel()
            self.timeout_deferred = reactor.callLater(TimerProtocol.timeout, self.transport.loseConnection)
 
    def start(self):
        self.started = True
        self.sendTime()
 
    def stop(self):
        self.started = False
 
    def sendTime(self):
        if self.started:
            self.encoder.writeElement(datetime.now())
            self.transport.write(self.stream.getvalue())
            self.stream.truncate()
 
            reactor.callLater(self.interval, self.sendTime)
 
 
class TimerFactory(Factory):
    protocol = TimerProtocol
    max_connections = 1000
 
    def __init__(self):
        self.number_of_connections = 0
 
 
class SocketPolicyProtocol(Protocol):
    """
    Serves strict policy file for Flash Player >= 9,0,124.
 
    @see: U{http://adobe.com/go/strict_policy_files}
    """
    def connectionMade(self):
        self.buffer = ''
 
    def dataReceived(self, data):
        self.buffer += data
 
        if self.buffer.startswith('<policy-file-request/>'):
            self.transport.write(self.factory.getPolicyFile(self))
            self.transport.loseConnection()
 
 
class SocketPolicyFactory(Factory):
    protocol = SocketPolicyProtocol
 
    def __init__(self, policy_file):
        """
        @param policy_file: Path to the policy file definition
        """
        self.policy_file = policy_file
 
    def getPolicyFile(self, protocol):
        return open(self.policy_file, 'rt').read()
 
 
host = 'localhost'
appPort = 8000
policyPort = 843
policyFile = 'socket-policy.xml'
 
 
if __name__ == '__main__':
    from optparse import OptionParser
 
    parser = OptionParser()
    parser.add_option("--host", default=host,
        dest="host", help="host address [default: %default]")
    parser.add_option("-a", "--app-port", default=appPort,
        dest="app_port", help="Application port number [default: %default]")
    parser.add_option("-p", "--policy-port", default=policyPort,
        dest="policy_port", help="Socket policy port number [default: %default]")
    parser.add_option("-f", "--policy-file", default=policyFile,
        dest="policy_file", help="Location of socket policy file [default: %default]")
    (opt, args) = parser.parse_args()
 
    print "Running Socket AMF gateway on %s:%s" % (opt.host, opt.app_port)
    print "Running Policy file server on %s:%s" % (opt.host, opt.policy_port)
 
    reactor.listenTCP(int(opt.app_port), TimerFactory(), interface=opt.host)
    reactor.listenTCP(int(opt.policy_port), SocketPolicyFactory(opt.policy_file),
                      interface=opt.host)
    reactor.run()