Hi,
I am currently writing a server prototype for an online game called "If I Were U" (GPL). It will
be using UDP and a MySQL db. I was successful in writing the code as a plug-in. I love the idea of
being able to seperate in different files the levels of abstraction. But I am not sure of how to
go about the following:
I have an iiwuServer class derived from DatagramProtocol. I defined the datagramReceived method.
This method calls one of my other classes's methods which returns a deferred object (this is where
the connection to the db happens). I am trying to set the callback function for this deferred
object and I want it to be a method of iiwuServer as I need to access the transport member object
which in its turn writes out a datagram to the client. And I am not sure how to set up the
callbackArgs for it (the "self" argument for methods is where I am confused).
What am I doing wrong?
Also, if you have a couple of minutes, can u look at my other three code segments (found after the
iiwuServer) and tell me if you see anything that should be changed. Don't worry, the code is not
that long. The thing is that in the documentation, each part (UDP, plug-in, deferred, etc...) are
very well explained. But when I tried to put all that together, I got a little confused as I did
not see any examples of UDP plug-ins or more complex deferred callback functions.
All these segments are actually files in a folder called UDPServer. If you prefer that I send you
the directory tarred and zipped, let me know. All that is left out is the empty __init__.py file
in the folder.
Thanks a lot,
Ib
http://www.iiwu.org
Here is the code for the protocol (file name: iiwuserverprotocol.py):
////////CODE START\\\\\\\\
############################
##This is where the UDP packets are recieved and then sent to the server logic
############################
from twisted.internet.protocol import DatagramProtocol
from UDPServer import iiwuserverlogic
class iiwuServer(DatagramProtocol):
iiwuservice = iiwuserverlogic.LoginService()
def sendingOutput(self, result, host, port):
"""
A callback for the deferred object returned
"""
self.transport.write(str(result) + "\n" + str(self) + "\n", (host, port))
return
def datagramReceived(self, data, (host, port)):
msg = data.split()
if len(msg) != 1 and len(msg) != 3:
self.sendingOutput("error" , host, port)
return
if msg[0] == "log" and len(msg) == 3:
user = msg[1]
pswd = msg[2]
self.iiwuservice.logUser(user, pswd, host, port).addCallback(self.sendingOutput(self,
host, port))
return
if msg[0] == "get":
self.iiwuservice.loggedUsers().addCallback(self.sendingOutput(self, host, port))
return
return
\\\\\\\\CODE END////////
Here is the code for the server's logic (file name: iiwuserverlogic.py):
////////CODE START\\\\\\\\
##############################
##This is where all the logic of the server lies
##############################
from twisted.python import components
from twisted.enterprise import adbapi
class IService(components.Interface):
"""
An object that recieves messages.
"""
class LoginService:
"""
Respond to different messages
"""
__implements__ = IService
def __init__(self):
"""
Setting up the db connection pool
"""
self.dbpool = adbapi.ConnectionPool("MySQLdb", 'database_name', 'login', 'password')
return
def mysqlQuery(self, q):
"""
Run a MySql query and return the result
"""
result = self.dbpool.runQuery(q)
return result #Returning a Deferred object
def logUser(self, name, pswd, ip, port):
"""
Connects to the DB and logs the user, returning nothing
"""
query = "INSERT INTO users (name, pswd, ip, port) VALUES (%s, %s, %s, %s)" % (name, pswd,
ip, port)
return self.mysqlQuery(query)
def loggedUsers(self):
"""
Connects to the DB and returns a list of the users logged in
"""
query = "SELECT * FROM users"
return self.mysqlQuery(query)
\\\\\\\\CODE END////////
Here is the code for the tap construction (file name: servertap.py):
////////CODE START\\\\\\\\
from twisted.application import internet # services that run TCP/SSL/etc.
from UDPServer import iiwuserverprotocol # Protocol
from UDPServer import iiwuserverlogic # Server code
from twisted.python import usage # twisted command-line processing
class Options(usage.Options):
"""
Defining options when building the application
"""
optParameters = [["port", "p", 8007, "Port number to listen on for iiwuServer protocol."]]
def makeService(config):
"""
Return a service that will be attached to the application.
"""
protocol = iiwuserverprotocol.iiwuServer()
port = int(config["port"]) # UCP port to listen on
# Finally, set up our protocol when events arrive on the specified port
return internet.UDPServer(port, protocol)
\\\\\\\\CODE END////////
Finally, here is the plugins.tml file:
////////CODE START\\\\\\\\
register("IIWU Server TAP Builder",
"UDPServer.servertap",
description="""
IIWU TAP builder module.
""" ,
type="tap",
tapname="iiwuserv")
\\\\\\\\CODE END////////
__________________________________
Do you Yahoo!?
New and Improved Yahoo! Mail - 100MB free storage!
http://promotions.yahoo.com/new_mail
In my client's app we've been having problems with database connections
going down; so far if that happens we need to restart the server to
reconnect to the DB. I looked at adbapi's implementation and noticed
that it wasn't doing anything special to notice lost connections. Then I
realized DBAPI2 doesn't actually specify a way to tell whether your
connection has gone down.
I've been trying to think of a way to at least work around this on a
per-app basis -- mine is using psycopg. It just raises either a
ProgrammingError or an OperationalError on cursor.execute. The brightest
idea we've come up with is to reconnect after N (~ 3) consecutive errors.
Any other ideas?
--
Twisted | Christopher Armstrong: International Man of Twistery
Radix | Release Manager, Twisted Project
---------+ http://radix.twistedmatrix.com/
1. Switch classes from:
class C:
__implements__ = IFoo,
to:
class C:
zope.interface.implements(IFoo)
and if you have third party subclasses that may depend on C having
__implements__, also add:
twisted.python.components.backwardsCompatImplements(C)
2. Using zope.interface APIs directly is better, e.g. IFoo.providedBy(o)
rather than components.implements(o, IFoo). But! If the object is third
party, it may be using __implements__, and if the class never got
processed by t.p.c it will not be hooked up to zope.interface at all.
So, you may want to do:
t.p.componets.fixClassImplements(o.__class__)
this will make sure that __implements__ declarations get converted to
new style implements declarations.
3. Basically all of t.p.c is deprecated except for registerAdapter and
the other APIs that talk to registry. Componentized is not, in theory,
but hopefully will be replaced soon.
--
Itamar Shtull-Trauring http://itamarst.org
Much thanks orbitz and radix. Went down the wrong path on something subtle.
I thought I had read in an example document, "d.callback" to the
reactor.callLater() whereas it turns out to be "callback" and not
"d.callback". I should have stopped and slept instead of going on sleepless
fumes!
Cheers,
Sergio
>From: Christopher Armstrong <radix(a)twistedmatrix.com>
>Reply-To: Twisted discussion stuff <twisted-python(a)twistedmatrix.com>
>To: Twisted discussion stuff <twisted-python(a)twistedmatrix.com>
>Subject: Re: [Twisted-Python] reactor.callLater always requires args
>object?
>Date: Wed, 21 Jul 2004 14:55:00 -0400
>
>Sergio Trejo wrote:
>>There's sure to be a good reason why, perhaps something utterly obvious to
>>most but as a newbie I'm still trying to grok as much as possible where
>>needed. Thanks for any clarification.
>
>*Deferreds* need a result, not callLater. As orbitz mentioned,
>reactor.callLater(3, checkForSanity) would work fine. d.callback, as well
>as all callbacks added to a Deferred with d.addCallback, always require at
>least one argument.
>
>--
> Twisted | Christopher Armstrong: International Man of Twistery
> Radix | Release Manager, Twisted Project
>---------+ http://radix.twistedmatrix.com/
><< signature.asc >>
>_______________________________________________
>Twisted-Python mailing list
>Twisted-Python(a)twistedmatrix.com
>http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
_________________________________________________________________
Tired of spam? Get advanced junk mail protection with MSN 8.
http://join.msn.com/?page=features/junkmail
I'm trying to be a good soldier by heeding the warning issued by the Twisted
gods warning strongly *not* to use defer.Deferred's setTimeout() and instead
using reactor.callLater
I've looked at the API for twisted.internet.defer.Deferred.callback and
twisted.internet.default.SelectReactor.callLater (which refers one to see
twisted.internet.interfaces.IReactorTime.callLater which I have also read).
I don't understand why at least one args object must always be supplied to
reactor.callLater, as in:
reactor.callLater(3, d.callback, "an unused arg")
even though the callback function:
d.addCallback(checkForSanity)
receives no args:
def checkForSanity():
print "this is a sanity test"
In order to get the reactor.callLater to perform the callback, I had to pass
in at least one arg:
def checkForSanity(ignoreMe):
print "this is a sanity test"
d = defer.Deferred()
d.addCallback(checkForSanity)
reactor.callLater(3, d.callback, "ignore me")
There's sure to be a good reason why, perhaps something utterly obvious to
most but as a newbie I'm still trying to grok as much as possible where
needed. Thanks for any clarification.
Serg
_________________________________________________________________
MSN 8 with e-mail virus protection service: 2 months FREE*
http://join.msn.com/?page=features/virus
>From: Stephen Waterbury <golux(a)comcast.net>
>Reply-To: Twisted discussion stuff <twisted-python(a)twistedmatrix.com>
>To: Twisted discussion stuff <twisted-python(a)twistedmatrix.com>
>Subject: Re: [Twisted-Python] Twisted gets mad freaky love from IEEE
>InternetComputing
>Date: Tue, 20 Jul 2004 22:41:27 -0400
>
>Daniel Burr wrote:
>>A very nice section on Twisted appears in this article about dynamic
>>languages and distributed systems.
>
>Particularly impressive since the author works for IONA, one of
>the main CORBA vendors. How refreshing! Apparently IONA is
>immune to the virulent open source paranoia that afflicts a
>certain monolithic operating system vendor whose president
>happens to be the richest earthling. ;)
Whose copyright holders of such an operating system announced a huge stock
buyback to try and ooh and ahhh its shareholders to thus try to give people
the warm fuzzy feelings that closed source still rules (which of course it
doesn't).
>
>Steve
>
>_______________________________________________
>Twisted-Python mailing list
>Twisted-Python(a)twistedmatrix.com
>http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
_________________________________________________________________
Tired of spam? Get advanced junk mail protection with MSN 8.
http://join.msn.com/?page=features/junkmail
A very nice section on Twisted appears in this article about dynamic
languages and distributed systems.
PEAK gets a nice mention as well.
Read it at:
http://dsonline.computer.org/0407/d/w4towp.htm
Naz
Radix -- this was an excellent suggestion - it works quite well. Thanks for
your trips. Its been interesting delving into the aspects of Avatars, the
Mind, Realms and Portals. Good stuff.
Sergio
>From: Christopher Armstrong <radix(a)twistedmatrix.com>
>Reply-To: Twisted discussion stuff <twisted-python(a)twistedmatrix.com>
>To: Twisted discussion stuff <twisted-python(a)twistedmatrix.com>
>Subject: Re: [Twisted-Python] PB - Dual Use Objects?
>Date: Fri, 16 Jul 2004 12:45:32 -0400
>
>Sergio Trejo wrote:
>>I'm curious, for those who use PB for their projects, do they make their
>>objects at each end of the wire dual use (meaning, both objects run a PB
>>Server and PB Client Factory such that each object can remotely call the
>>other), or do most people stick to a typical client-server model wherby
>>the PB Server Factory object just waits for requests from the Client and
>>does not attempt to initiate any messages to the client?
>>
>>I ask because as a newbie to Twisted, I also started reading the
>>twisted.flow HowTo and it looks like there are some really interesting
>>things that could be done with PB. I have an app in mind whereby a PB
>>Client (A) triggers a PB Server, and then the PB Server expects incoming
>>data from another PB Client (B) but the data that comes in from B is
>>useful to pass back to A (all in a deferred manner however). Therefore the
>>PB Server acts as an intermediary. But this could get really hairy if I
>>turned the PB Server into a server handling multiple requests from PB
>>Clients of type A and PB Clients of type B (could look like a spaghetti
>>bowl f the Server is required to route data from the Bs to the As) so
>>maybe better to stick with a typical client-server model.
>
>No, this is very simple. First of all, you need the Bs to pass a "mind"
>object to pb.login(). It'll probably be a Referenceable subclass instance.
>You'll get this mind object passed to your Realm's requestAvatar method, so
>you can save it wherever relevant there. Let's pretend this object has a
>messageFromAnA remote method.
>
>Then the As connect, and do middleman.callRemote('doSomethingToAB'):
>
>def remote_doSomethingToAB(self):
> return self.mind.callRemote('messageFromAnA')
>
>callRemote will return a Deferred that fires with the result from B's
>messageFromAnA method, and PB will pass this result off as the result to A,
>so A is getting the result that B returned.
>
>--
> Twisted | Christopher Armstrong: International Man of Twistery
> Radix | Release Manager, Twisted Project
>---------+ http://radix.twistedmatrix.com/
><< signature.asc >>
>_______________________________________________
>Twisted-Python mailing list
>Twisted-Python(a)twistedmatrix.com
>http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python
_________________________________________________________________
STOP MORE SPAM with the new MSN 8 and get 2 months FREE*
http://join.msn.com/?page=features/junkmail