Пример #1
0
 def __init__(self, name, id, hidden, autoClose, master):
     self.name = name
     self.id = id
     self.hidden = hidden
     self.autoClose = autoClose
     self.master = master
     self.connections = MultikeyDict()
Пример #2
0
 def __init__(self, factory):
     self.name = DUMMY_PLAYER_NAME
     self.id = factory.userPool.pop()
     self.channels = MultikeyDict()
     self.isAccepted = True
     self.loggedIn = True
     self.factory = factory
Пример #3
0
 def startFactory(self):
     self.connections = MultikeyDict()
     self.channels = MultikeyDict()
     self.userPool = IDPool()
     self.channelPool = IDPool()
     if self.ping:
         self._pinger = pinger = LoopingCall(self.globalPing)
         pinger.start(self.pingTime, False)
Пример #4
0
 def startFactory(self):
     ServerFactory.startFactory(self)
     channels = MultikeyDict()
     self.dummy = DummyProtocol(self)
Пример #5
0
class ServerFactory(protocol.ServerFactory):
    """
    The server factory.
    
    @ivar channelClass: This is the channel class that will be used when
        creating a new channel. Subclass L{ServerChannel} and replace this
        attribute if you want to change the behaviour of channels.
    @ivar maxPing: This is the time the client has to respond
        to pings (in seconds). Can be a number or None for no max ping (default)
    @ivar pingTime: The interval between pings in seconds
    @ivar maxUsers: The max number of users allowed on the server.
    @ivar timeOut: The number of seconds the client has to send a Hello packet
        before being disconnected. Can be a number or None for no timeout
    @ivar welcomeMessage: The message sent to accepted clients.
    @ivar ping: If True, pinging will be enabled on the server
    @ivar channelListing: If True, channelListing is enabled on the server
    @ivar masterRights: If True, this enables the autoclose feature for
        clients when creating channels
    """
    channelClass = ServerChannel
    timeOut = 8
    pingTime = 8
    maxPing = None
    maxUsers = 1000
    welcomeMessage = 'Welcome! Server is running pylacewing %s (%s)' % (
        lacewing.__version__, sys.platform)
    
    datagram = None
    ping = True
    channelListing = True
    masterRights = False
    
    _pinger = None

    def startFactory(self):
        self.connections = MultikeyDict()
        self.channels = MultikeyDict()
        self.userPool = IDPool()
        self.channelPool = IDPool()
        if self.ping:
            self._pinger = pinger = LoopingCall(self.globalPing)
            pinger.start(self.pingTime, False)
    
    def globalPing(self):
        """
        Pings all clients currently connected to the server
        """
        for connection in self.connections.values():
            connection.ping()
    
    def getWelcomeMessage(self, connection):
        """
        This method is called when a connection has been accepted, and
        a welcome message has to be sent. The default implementation just
        returns L{welcomeMessage}, but override this method to change that
        behaviour.
        @param connection: Connection that has been accepted
        @type connection: L{ServerProtocol} object
        @rtype: str
        """
        return self.welcomeMessage
    
    def createChannel(self, name, hidden, autoClose, master):
        if not self.masterRights:
            autoClose = False
        try:
            channel, = self.channels[name]
        except KeyError:
            id = self.channelPool.pop()
            channel = self.channelClass(name, id, hidden, autoClose, master)
            self.channels[name, id] = channel
            self.channelAdded(channel)
        return channel
    
    def destroyChannel(self, channel):
        del self.channels[channel]
        self.channelRemoved(channel)

    def channelRemoved(self, channel):
        """
        Called when a channel has no users in it, and
        is therefore removed.
        @arg channel: The channel that is being removed.
        """

    def channelAdded(self, channel):
        """
Пример #6
0
class ServerChannel(object):
    """
    Represents a channel.

    @ivar id: ID of the channel.
    @ivar name: The name of the channel.
    @ivar connections: List of the clients in the channel.
    @ivar autoClose: True if this channel will close after the master leaves
    @ivar master: The master connection of this channel
    @type master: L{ServerProtocol} object
    """

    id = None
    name = None
    hidden = False
    autoClose = False
    master = None

    def __init__(self, name, id, hidden, autoClose, master):
        self.name = name
        self.id = id
        self.hidden = hidden
        self.autoClose = autoClose
        self.master = master
        self.connections = MultikeyDict()

    def addConnection(self, connection):
        """
        Add a client to the channel, and notify the other clients.

        @param connection: The protocol instance to add.
        """

        toClient = server.Peer()
        toClient.name = connection.name
        toClient.peer = connection.id
        toClient.channel = self.id
        toClient.isMaster = connection is self.master
        self.sendLoader(toClient)
        self.connections[connection.name, connection.id] = connection

    def removeConnection(self, connection):
        """
        Remove a client from the channel, and notify the other
        clients.

        @param connection: The protocol instance to remove.
        """

        # tell the other clients this client is leaving
        toClient = server.Peer()
        toClient.peer = connection.id
        toClient.channel = self.id
        self.sendLoader(toClient, [connection])
        # remove client
        del self.connections[connection]
        
        # close the channel if autoClose is set, and the removed client was
        # the master
        if connection is self.master and self.autoClose:
            close = len(self.connections) > 0
            for connection in self.connections.values():
                connection.leaveChannel(self)
                connection.channelLeft(self)
            return close
        
        return len(self.connections) > 0

    def sendMessage(self, message, subchannel = 0, fromConnection = None,
                    asObject = False, typeName = None, **settings):
        """
        Send a channel message from the given protocol instance.

        @param fromConnection: The client that the message is sent
        from (or None if the message is from the server).
        @param message: The message to send.
        @type message: str/number/ByteReader
        @param subchannel: The subchannel to send the message on.
        @type subchannel: number
        @param typeName: If not specified, the type will be 
        automatically detected (see L{lacewing.packetloaders.common.DATA_TYPES}
        for possible values)
        """
        if typeName is None:
            typeName = detectType(message)
        if asObject:
            if fromConnection is None:
                newMessage = server.ObjectServerChannelMessage()
            else:
                newMessage = server.ObjectChannelMessage()
        else:
            if fromConnection is None:
                newMessage = server.BinaryServerChannelMessage()
            else:
                newMessage = server.BinaryChannelMessage()
        newMessage.channel = self.id
        newMessage.value = message
        newMessage.subchannel = subchannel
        if fromConnection is not None:
            newMessage.peer = fromConnection.id
        newMessage.setDataType(typeName)
        self.sendLoader(newMessage, [fromConnection], **settings)

    def sendPrivateMessage(self, message, subchannel, sender, recipient, 
                           asObject = False, typeName = None, **settings):
        """
        Send a message from this client to a recipient

        @type message: str/number/ByteReader
        @param subchannel: The subchannel of the message in the range 0-256
        @param sender: Sending connection
        @type sender: L{ServerProtocol} object
        @param recipient: Connection to send message to
        @type recipient: L{ServerProtocol} object
        @param typeName: If not specified, the type will be 
        automatically detected (see L{lacewing.packetloaders.common.DATA_TYPES}
        for possible values)
        """
        if typeName is None:
            typeName = detectType(message)
        if asObject:
            newMessage = server.ObjectPeerMessage()
        else:
            newMessage = server.BinaryPeerMessage()
        newMessage.channel = self.id
        newMessage.value = message
        newMessage.subchannel = subchannel
        newMessage.peer = sender.id
        newMessage.setDataType(typeName)
        recipient.sendLoader(newMessage, **settings)

    def sendLoader(self, type, notClients = [], **settings):
        """
        Send the specified type to all the clients in the channel,
        apart from notClients if specified.
        """

        toClients = [connection for connection in self.connections.values()
                    if connection not in notClients]

        for client in toClients:
            client.sendLoader(type, **settings)
Пример #7
0
 def __init__(self, name, id, factory):
     self.name = name
     self.id = id
     self.factory = factory
     
     self.connections = MultikeyDict()
Пример #8
0
class Channel(object):
    name = None
    id = None
    factory = None
    
    connections = None
    
    def __init__(self, name, id, factory):
        self.name = name
        self.id = id
        self.factory = factory
        
        self.connections = MultikeyDict()
    
    def addConnection(self, connection):
        self.connections[connection.name, connection.id] = connection
        connection.channels[self.name, self.id] = self

        newJoined = ChannelJoined()
        newJoined.setChannel(self)
        newJoined.setConnection(connection)
        connection.sendLoader(newJoined)
        
        newExists = PlayerExists()
        newExists.setChannel(self)
        
        newJoined = PlayerJoined()
        newJoined.setChannel(self)
        newJoined.setConnection(connection)
        
        for otherConnection in self.connections.values():
            if otherConnection != connection:
                newExists.setConnection(otherConnection)
                connection.sendLoader(newExists)
                otherConnection.sendLoader(newJoined)
        
    def removeConnection(self, connection):
        newLeft = PlayerLeft()
        newLeft.setChannel(self)
        newLeft.setConnection(connection)
        self.sendLoader(newLeft)
        
        del self.connections[connection]
        del connection.channels[self]
        
        return len(self.connections) != 0
    
    def sendMessage(self, connection, value, subchannel, type = None, toClient = None):
        newValue = Message(**connection.settings)
        newValue.type = type or detectType(value)
        newValue.value = value
        newMessage = FromChannelMessage()
        newMessage.setChannel(self)
        newMessage.setConnection(connection)
        newMessage.message = newValue
        newMessage.subchannel = subchannel
        if toClient:
            toClient.sendLoader(newMessage)
        else:
            self.sendLoader(newMessage, connection)
        
    def sendLoader(self, loader, fromClient = None):
        for connection in self.connections.values():
            if connection != fromClient:
                connection.sendLoader(loader)
        
    def getMaster(self):
        return self.connections.values()[0]