Hi everyone. I'm writing a Twisted based daemon for a simple text-based multiplayer game. The game logic goes like this. The client sends a string in a particular format (command.arguments (also separated by period)) to the server. The server receives that string, split it, and run the command along with the arguments. I already made it working.
Some of the commands called (login for example) has to get data from database. I'm using Twistar to make things fancy. Here's where I found some difficulties. The function which calls the available commands returns the result of the called command. The problem is that I don't know how to make my login function to return the result of the query.
Simply, what I want : send strings (or list, or number, or whatever) gained from the database to the client.
What I get now : the server sends a deferred object or an empty string or list (I've tried some ways to send things to the client).
I know it sounds so newbie, but this is my first Twisted program, and I'm still learning, so please spare me.
Well, I think the scripts will make things clearer:
The server.py.
[spoiler]
from twisted.application import internet, service
import protocols, services
udp_port = 10000
multicast_addr = '234.0.0.1'
dbuser = 'root'
dbpass = 'password'
main_service = service.MultiService()
game_service = services.GameService(dbuser, dbpass)
game_service.setServiceParent(main_service)
udp_service = internet.MulticastServer(udp_port, protocols.MulticastGameProtocol(multicast_addr, game_service), listenMultiple=True)
udp_service.setServiceParent(main_service)
application = service.Application('Celestial Eclipse')
main_service.setServiceParent(application)
[/spoiler]
The protocols.py
[spoiler]
from twisted.internet.protocol import DatagramProtocol
class MulticastGameProtocol(DatagramProtocol):
def __init__(self, multicast_addr, service):
self.multicast_addr = multicast_addr
self.service = service
def startProtocol(self):
self.transport.setTTL(5)
self.transport.joinGroup(self.multicast_addr)
def datagramReceived(self, datagram, address):
print 'Datagram %s received from %s' % (repr(datagram), repr(address))
if '.' not in datagram:
return 'Invalid command format.'
celcommand_name, arguments = datagram.split('.', 1)
self.celcommandRequestReceived(celcommand_name, arguments, address)
def celcommandRequestReceived(self, celcommand_name, arguments, address):
command_result = self.doCommand(celcommand_name, arguments)
if command_result is not None:
self.transport.write(command_result, address)
def doCommand(self, celcommand_name, arguments):
submitted_command = getattr(self, 'celcommand_%s' % (celcommand_name), None)
if submitted_command is None:
return 'Invalid command.'
try:
#return 'COMMAND SUCCESS!!!'
return repr(submitted_command(arguments))
except:
#return 'Command failed.'
return repr(submitted_command(arguments))
def celcommand_login(self, arguments):
username, password = arguments.split('.', 1)
return self.service.login(username, password)
[/spoiler]
The services.py
[spoiler]
from twisted.application import service
from twisted.python import log
from twisted.internet import defer
from twistar.dbobject import DBObject
class Users(DBObject):
pass
class GameService(service.Service):
def __init__(self, dbuser, dbpass):
self.dbuser = dbuser
self.dbpass = dbpass
def startService(self):
service.Service.startService(self)
from twisted.enterprise import adbapi
from twistar.registry import Registry
Registry.DBPOOL = adbapi.ConnectionPool('MySQLdb', user='root', passwd='password', db='test')
self.user = Users()
log.msg('Made connection to database.')
self.loginResult = None
def getLogin(self, username, password):
return self.user.find(where=['username="%s" AND password_hash="%s"' % (username, password)], limit=1)
def login(self, username, password):
#self.loginResult = []
self.d = self.getLogin(username, password)
def checkLogin(query_result):
if query_result is None:
return 'Login failed!'
else:
print '%s logged in' % (query_result.username)
return query_result.username
#self.loginResult = query_result.username
#self.loginResult.append(query_result)
self.d.addCallback(checkLogin)
#It has to return something, but I don't know what to return.
#return self.loginResult
[/spoiler]
There's no complicated logic yet. I started writing this thing just three days ago.
The deferred does fire. It prints the "bla bla bla logged in" properly.
The client is just a simple client which sends 'login.Sky Warden.123'. The arguments will be separated by the '.' as well.
I think that's all. Maybe it's just me who don't fully understand deferreds, or it's just a logic hole. Or maybe both. XD
Thank you everyone.