My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
Tutorials  
Various tutorials and code samples
Featured
Updated Apr 22, 2011 by matp...@gmail.com

Tutorials

This page should get you started on pylacewing development via various tutorials and code samples

Installing pylacewing

Dependencies

First off, you should get the latest Python version. Don't use Python 3.x since pylacewing doesn't work with it and neither does Twisted (AFAIK). Once Python is installed, install Twisted (Twisted also depends on zope.interface, so in case you get errors about that, install it). Next up, get the newest pylacewing release and install it by the usual "python setup.py install"-method.

Server

Creating a minimal server

First off, we're gonna import the Twisted reactor and the vital pylacewing stuff. Basically, a ServerProtocol instance is a unique connection, and a ServerFactory instance is the actual "server". The ServerDatagram class handles UDP packets. The ServerFactory is and should be responsible for managing things between clients.

from twisted.internet import reactor

from lacewing.server import ServerProtocol, ServerFactory, ServerDatagram

Then, we're going to subclass ServerProtocol and ServerFactory so we can change their functionality (even though for this tutorial, we're not going to do anything: we'll do that in another tutorial).

class MyProtocol(ServerProtocol):
    pass

class MyFactory(ServerFactory):
    protocol = MyProtocol

Now we're going to actually run the server by first instantiating the factory, then make it listen on port 6121 (for both TCP and UDP - the Lacewing protocol requires both), and finally, run the reactor:

newFactory = MyFactory()
reactor.listenTCP(6121, newFactory)
reactor.listenUDP(6121, ServerDatagram(newFactory))
reactor.run()

Full code:

from twisted.internet import reactor

from lacewing.server import ServerProtocol, ServerFactory, ServerDatagram

class MyProtocol(ServerProtocol):
    pass

class MyFactory(ServerFactory):
    protocol = MyProtocol

newFactory = MyFactory()
reactor.listenTCP(6121, newFactory)
reactor.listenUDP(6121, ServerDatagram(newFactory))
reactor.run()

Congratulations! Your very first server should be up and running now!

Sending server messages

To send messages to peers, we can use the ServerProtocol.sendMessage method: http://mp2.dk/pylacewing/docs/lacewing.server.ServerProtocol-class.html#sendMessage

So, the first argument is the message to send, second is subchannel, and the rest are optional (asDatagram will send the message via UDP if it has been enabled).

from twisted.internet import reactor

from lacewing.server import ServerProtocol, ServerFactory, ServerDatagram

class MyProtocol(ServerProtocol):
    def connectionAccepted(self, hello):
        # fired when a new peer connection 
        # has been accepted
        self.sendMessage('Hello', 1)

class MyFactory(ServerFactory):
    protocol = MyProtocol

newFactory = MyFactory()
reactor.listenTCP(6121, newFactory)
reactor.listenUDP(6121, ServerDatagram(newFactory))
reactor.run()

This will send the string message "Hello" on subchannel 1 to connecting peers.

Receiving peer messages

To handle messages sent directly to the server, we override the ServerProtocol.messageReceived method: http://mp2.dk/pylacewing/docs/lacewing.server.ServerProtocol-class.html#messageReceived

The argument passed to the method is a ClientMessage instance that has the following attributes:

  • value
  • subchannel
  • settings['isDatagram'] (whether the message was received with UDP)

The following server example will echo back messages sent to it:

from twisted.internet import reactor

from lacewing.server import ServerProtocol, ServerFactory

class MyProtocol(ServerProtocol):
    def messageReceived(self, message):
        print 'Received:', message.value, 'on', message.subchannel
        self.sendMessage(message.value, message.subchannel)

class MyFactory(ServerFactory):
    protocol = MyProtocol

newFactory = MyFactory()
reactor.listenTCP(6121, newFactory)
reactor.listenUDP(6121, ServerDatagram(newFactory))
reactor.run()

Iterating over all peers

To iterate over all peers connected to the server, we have to access the ServerFactory.connections dict.

The following server example will send a message to all peers when a new peer connection has been accepted:

from twisted.internet import reactor

from lacewing.server import ServerProtocol, ServerFactory, ServerDatagram

class MyProtocol(ServerProtocol):
    def connectionAccepted(self, hello):
        self.factory.sendGlobal()

class MyFactory(ServerFactory):
    protocol = MyProtocol

    def sendGlobal(self):
        for peer in self.connections.values():
            peer.sendMessage('Peer connected', 1)

newFactory = MyFactory()
reactor.listenTCP(6121, newFactory)
reactor.listenUDP(6121, ServerDatagram(newFactory))
reactor.run()

Simulating lag

Sometimes, it might be a good idea to simulate lag between a server and a client to properly implement client-side prediction or likewise. This can be done by delaying the amount of time it takes for data to arrive at the server, by hooking into the dataReceived method of protocols (for more info, see Twisted documentation). Here's some code that does exactly that:

LATENCY = 1 # in seconds

from twisted.internet import reactor

from lacewing.server import ServerProtocol, ServerFactory, ServerDatagram

class MyProtocol(ServerProtocol):
    def dataReceived(self, data):
        reactor.callLater(LATENCY, ServerProtocol.dataReceived, self, data)

class MyFactory(ServerFactory):
    protocol = MyProtocol

newFactory = MyFactory()
reactor.listenTCP(6121, newFactory)
reactor.listenUDP(6121, ServerDatagram(newFactory))
reactor.run()

Disconnecting clients

To disconnect a client, you can use the ServerProtocol.disconnect method: http://mp2.dk/pylacewing/docs/lacewing.server.ServerProtocol-class.html#disconnect

disconnect() accepts some optional arguments (including a string reason for denial).

The first argument is the "response" argument, which indicates which request this is a response to. They have the following names:

  • CONNECT - Response to a connection request
  • SET_NAME - Response to a name set request
  • JOIN_CHANNEL - Response to a channel join request
  • LEAVE_CHANNEL - Response to a channel leave request
  • CHANNEL_LIST - Response to a channel list request

The constants can be imported from lacewing.constants. The second parameter is the string denial reason - useful for telling the back-end application what went wrong. Some of the responses have obligatory parameters - check the source for more info.

The following example will disconnect a peer if it tries to use the name "Moderator"

from twisted.internet import reactor
from lacewing.constants import SET_NAME
from lacewing.server import ServerProtocol, ServerFactory, ServerDatagram

class MyProtocol(ServerProtocol):
    def acceptLogin(self, name):
        # called when a peer is trying to login
        # with a name. Return False to ignore.
        if name == 'Moderator':
            self.disconnect(SET_NAME, 'Invalid name!')
            return False

class MyFactory(ServerFactory):
    protocol = MyProtocol

newFactory = MyFactory()
reactor.listenTCP(6121, newFactory)
reactor.listenUDP(6121, ServerDatagram(newFactory))
reactor.run()

XXX finish :)


Sign in to add a comment
Powered by Google Project Hosting