· 8 years ago · Jun 06, 2018, 11:00 AM
1#
2# -*- py-indent-offset: 4; coding: iso-8859-1 -*-
3#
4# Copyright (C) 2006, 2007 Loic Dachary <loic@dachary.org>
5# Copyright (C) 2004, 2005, 2006 Mekensleep
6#
7# Mekensleep
8# 24 rue vieille du temple
9# 75004 Paris
10# licensing@mekensleep.com
11#
12# This program is free software; you can redistribute it and/or modify
13# it under the terms of the GNU General Public License as published by
14# the Free Software Foundation; either version 2 of the License, or
15# (at your option) any later version.
16#
17# This program is distributed in the hope that it will be useful,
18# but WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20# GNU General Public License for more details.
21#
22# You should have received a copy of the GNU General Public License
23# along with this program; if not, write to the Free Software
24# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
25#
26# Authors:
27# Loic Dachary <loic@gnu.org>
28# Henry Precheur <henry@precheur.org> (2004)
29# Cedric Pinson <cpinson@freesheep.org>
30
31from os.path import exists
32from types import *
33from string import split, join
34import time
35import os
36import operator
37import re
38from traceback import print_exc
39
40from MySQLdb.cursors import DictCursor
41from MySQLdb.constants import ER
42
43from OpenSSL import SSL
44
45try:
46 from OpenSSL import SSL
47 HAS_OPENSSL=True
48except:
49 print "openSSL not available."
50 HAS_OPENSSL=False
51
52
53from twisted.application import service
54from twisted.internet import protocol, reactor, defer
55try:
56 # twisted-2.0
57 from zope.interface import Interface, implements
58except ImportError:
59 # twisted-1.3 forwards compatibility
60 def implements(interface):
61 frame = sys._getframe(1)
62 locals = frame.f_locals
63
64 # Try to make sure we were called from a class def
65 if (locals is frame.f_globals) or ('__module__' not in locals):
66 raise TypeError(" can be used only from a class definition.")
67
68 if '__implements__' in locals:
69 raise TypeError(" can be used only once in a class definition.")
70
71 locals['__implements__'] = interface
72
73 from twisted.python.components import Interface
74
75from twisted.python import components
76
77from pokerengine.pokertournament import *
78from pokerengine.pokercards import PokerCards
79
80from pokernetwork.server import PokerServerProtocol
81from pokernetwork.user import checkName, checkPassword
82from pokernetwork.pokerdatabase import PokerDatabase
83from pokernetwork.pokerpackets import *
84from pokernetwork.pokertable import PokerTable
85from pokernetwork import pokeravatar
86from pokernetwork.user import User
87from pokernetwork import pokercashier
88
89UPDATE_TOURNEYS_SCHEDULE_DELAY = 10 * 60
90CHECK_TOURNEYS_SCHEDULE_DELAY = 60
91DELETE_OLD_TOURNEYS_DELAY = 15 * 60
92
93class IPokerService(Interface):
94
95 def createAvatar(self):
96 """ """
97
98 def destroyAvatar(self, avatar):
99 """ """
100
101class IPokerFactory(Interface):
102
103 def createAvatar(self):
104 """ """
105
106 def destroyAvatar(self, avatar):
107 """ """
108
109 def buildProtocol(self, addr):
110 """ """
111
112class PokerFactoryFromPokerService(protocol.ServerFactory):
113
114 implements(IPokerFactory)
115
116 protocol = PokerServerProtocol
117
118 def __init__(self, service):
119 self.service = service
120 self.verbose = service.verbose
121
122 def createAvatar(self):
123 """ """
124 return self.service.createAvatar()
125
126 def destroyAvatar(self, avatar):
127 """ """
128 return self.service.destroyAvatar(avatar)
129
130components.registerAdapter(PokerFactoryFromPokerService,
131 IPokerService,
132 IPokerFactory)
133
134class PokerService(service.Service):
135
136 implements(IPokerService)
137
138 def __init__(self, settings):
139 self.settings = settings
140 self.verbose = self.settings.headerGetInt("/server/@verbose")
141 self.delays = settings.headerGetProperties("/server/delays")[0]
142 self.db = None
143 self.cashier = None
144 self.poker_auth = None
145 self.timer = {}
146 self.down = True
147 self.shutdown_deferred = None
148
149 def startService(self):
150 self.db = PokerDatabase(self.settings)
151 self.cleanupCrashedTables()
152 self.cleanUp(temporary_users = self.settings.headerGet("/server/users/@temporary"))
153 self.cashier = pokercashier.PokerCashier(self.settings)
154 self.cashier.setDb(self.db)
155 self.poker_auth = PokerAuth(self.db, self.settings)
156 self.dirs = split(self.settings.headerGet("/server/path"))
157 self.serial2client = {}
158 self.avatars = []
159 self.tables = []
160 self.table_serial = 100
161 self.shutting_down = False
162 self.simultaneous = self.settings.headerGetInt("/server/@simultaneous")
163 self._ping_delay = self.settings.headerGetInt("/server/@ping")
164 self.chat = self.settings.headerGet("/server/@chat") == "yes"
165 for description in self.settings.headerGetProperties("/server/table"):
166 self.createTable(0, description)
167 self.cleanupTourneys()
168 self.updateTourneysSchedule()
169 self.messageCheck()
170 self.poker_auth.SetLevel(PACKET_POKER_SEAT, User.REGULAR)
171 self.poker_auth.SetLevel(PACKET_POKER_GET_USER_INFO, User.REGULAR)
172 self.poker_auth.SetLevel(PACKET_POKER_GET_PERSONAL_INFO, User.REGULAR)
173 self.poker_auth.SetLevel(PACKET_POKER_PLAYER_INFO, User.REGULAR)
174 self.poker_auth.SetLevel(PACKET_POKER_TOURNEY_REGISTER, User.REGULAR)
175 self.poker_auth.SetLevel(PACKET_POKER_HAND_SELECT_ALL, User.ADMIN)
176 service.Service.startService(self)
177 self.down = False
178
179 def stopServiceFinish(self, x):
180 if self.cashier: self.cashier.close()
181 if self.db: self.db.close()
182 if self.poker_auth: self.poker_auth.db = None
183 service.Service.stopService(self)
184
185 def stopService(self):
186 deferred = self.shutdown()
187 deferred.addCallback(lambda x: reactor.disconnectAll())
188 deferred.addCallback(self.stopServiceFinish)
189 return deferred
190
191 def cancelTimer(self, key):
192 if self.timer.has_key(key):
193 if self.verbose > 3: print "cancelTimer " + key
194 timer = self.timer[key]
195 if timer.active():
196 timer.cancel()
197 del self.timer[key]
198
199 def shutdown(self):
200 self.shutting_down = True
201 self.cancelTimer('checkTourney')
202 self.cancelTimer('updateTourney')
203 self.cancelTimer('messages')
204 self.shutdown_deferred = defer.Deferred()
205 reactor.callLater(0.01, self.shutdownCheck)
206 return self.shutdown_deferred
207
208 def shutdownCheck(self):
209 if self.down:
210 if self.shutdown_deferred:
211 self.shutdown_deferred.callback(True)
212 return
213
214 playing = 0
215 for table in self.tables:
216 if not table.game.isEndOrNull():
217 playing += 1
218 if self.verbose and playing > 0:
219 print "Shutting down, waiting for %d games to finish" % playing
220 if playing <= 0:
221 if self.verbose:
222 print "Shutdown immediately"
223 self.down = True
224 self.shutdown_deferred.callback(True)
225 self.shutdown_deferred = False
226 else:
227 reactor.callLater(10, self.shutdownCheck)
228
229 def isShuttingDown(self):
230 return self.shutting_down
231
232 def stopFactory(self):
233 pass
234
235 def createAvatar(self):
236 avatar = pokeravatar.PokerAvatar(self)
237 self.avatars.append(avatar)
238 return avatar
239
240 def destroyAvatar(self, avatar):
241 if avatar in self.avatars:
242 self.avatars.remove(avatar)
243 else:
244 print "*ERROR* PokerService: avatar %s is not in the list of known avatars" % str(avatar)
245 avatar.connectionLost("Disconnected")
246
247 def sessionStart(self, serial, ip):
248 if self.verbose > 2: print "PokerService::sessionStart(%d, %s): " % ( serial, ip )
249 cursor = self.db.cursor()
250 sql = "insert into session ( user_serial, started, ip ) values ( %d, %d, '%s')" % ( serial, time.time(), ip )
251 cursor.execute(sql)
252 if cursor.rowcount != 1: print " *ERROR* modified %d rows (expected 1): %s" % ( cursor.rowcount, sql )
253 cursor.close()
254 return True
255
256 def sessionEnd(self, serial):
257 if self.verbose > 2: print "PokerService::sessionEnd(%d): " % ( serial )
258 cursor = self.db.cursor()
259 sql = "insert into session_history ( user_serial, started, ended, ip ) select user_serial, started, %d, ip from session where user_serial = %d" % ( time.time(), serial )
260 cursor.execute(sql)
261 if cursor.rowcount != 1: print " *ERROR* a) modified %d rows (expected 1): %s" % ( cursor.rowcount, sql )
262 sql = "delete from session where user_serial = %d" % serial
263 cursor.execute(sql)
264 if cursor.rowcount != 1: print " *ERROR* b) modified %d rows (expected 1): %s" % ( cursor.rowcount, sql )
265 cursor.close()
266 return True
267
268 def auth(self, name, password, roles):
269 for (serial, client) in self.serial2client.iteritems():
270 if client.getName() == name and roles.intersection(client.roles):
271 if self.verbose: print "PokerService::auth: %s attempt to login more than once with similar roles %s" % ( name, roles.intersection(client.roles) )
272 return ( False, "Already logged in from somewhere else" )
273 return self.poker_auth.auth(name, password)
274
275 def updateTourneysSchedule(self):
276 if self.verbose > 3: print "updateTourneysSchedule"
277 cursor = self.db.cursor(DictCursor)
278
279 sql = ( " SELECT * FROM tourneys_schedule WHERE " +
280 " active = 'y' AND " +
281 " ( respawn = 'y' OR " +
282 " register_time < UNIX_TIMESTAMP(NOW()) )" )
283 cursor.execute(sql)
284 result = cursor.fetchall()
285 self.tourneys_schedule = dict(zip(map(lambda schedule: schedule['serial'], result), result))
286 cursor.close()
287 self.checkTourneysSchedule()
288 self.cancelTimer('updateTourney')
289 self.timer['updateTourney'] = reactor.callLater(UPDATE_TOURNEYS_SCHEDULE_DELAY, self.updateTourneysSchedule)
290
291 def checkTourneysSchedule(self):
292 if self.verbose > 3: print "checkTourneysSchedule"
293 #
294 # Respawning tournaments
295 #
296 for schedule in filter(lambda schedule: schedule['respawn'] == 'y', self.tourneys_schedule.values()):
297 schedule_serial = schedule['serial']
298 if ( not self.schedule2tourneys.has_key(schedule_serial) or
299 not filter(lambda tourney: tourney.state == TOURNAMENT_STATE_REGISTERING, self.schedule2tourneys[schedule_serial]) ):
300 self.spawnTourney(schedule)
301 #
302 # One time tournaments
303 #
304 now = time.time()
305 one_time = []
306 for serial in self.tourneys_schedule.keys():
307 schedule = self.tourneys_schedule[serial]
308 if ( schedule['respawn'] == 'n' and
309 int(schedule['register_time']) < now ):
310 one_time.append(schedule)
311 del self.tourneys_schedule[serial]
312 for schedule in one_time:
313 self.spawnTourney(schedule)
314
315 #
316 # Update tournaments with time clock
317 #
318 for tourney in filter(lambda tourney: tourney.sit_n_go == 'n', self.tourneys.values()):
319 tourney.updateRunning()
320 #
321 # Forget about old tournaments
322 #
323 for tourney in filter(lambda tourney: tourney.state in ( TOURNAMENT_STATE_COMPLETE, TOURNAMENT_STATE_CANCELED), self.tourneys.values()):
324 if now - tourney.finish_time > DELETE_OLD_TOURNEYS_DELAY:
325 self.deleteTourney(tourney)
326
327 self.cancelTimer('checkTourney')
328 self.timer['checkTourney'] = reactor.callLater(CHECK_TOURNEYS_SCHEDULE_DELAY, self.checkTourneysSchedule)
329
330 def spawnTourney(self, schedule):
331 cursor = self.db.cursor()
332 cursor.execute("INSERT INTO tourneys "
333 " (schedule_serial, name, description_short, description_long, players_quota, players_min, variant, betting_structure, seats_per_game, player_timeout, currency_serial, prize_min, bailor_serial, buy_in, rake, sit_n_go, breaks_interval, rebuy_delay, add_on, add_on_delay, start_time)"
334 " VALUES "
335 " (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s )",
336 ( schedule['serial'],
337 schedule['name'],
338 schedule['description_short'],
339 schedule['description_long'],
340 schedule['players_quota'],
341 schedule['players_min'],
342 schedule['variant'],
343 schedule['betting_structure'],
344 schedule['seats_per_game'],
345 schedule['player_timeout'],
346 schedule['currency_serial'],
347 schedule['prize_min'],
348 schedule['bailor_serial'],
349 schedule['buy_in'],
350 schedule['rake'],
351 schedule['sit_n_go'],
352 schedule['breaks_interval'],
353 schedule['rebuy_delay'],
354 schedule['add_on'],
355 schedule['add_on_delay'],
356 schedule['start_time'] ) )
357 if self.verbose > 2: print "spawnTourney: " + str(schedule)
358 #
359 # Accomodate with MySQLdb versions < 1.1
360 #
361 if hasattr(cursor, "lastrowid"):
362 tourney_serial = cursor.lastrowid
363 else:
364 tourney_serial = cursor.insert_id()
365 if schedule['respawn'] == 'n':
366 cursor.execute("UPDATE tourneys_schedule SET active = 'n' WHERE serial = %s" % schedule['serial'])
367 cursor.close()
368 self.spawnTourneyInCore(schedule, tourney_serial, schedule['serial'])
369
370 def spawnTourneyInCore(self, tourney_map, tourney_serial, schedule_serial):
371 tourney_map['start_time'] = int(tourney_map['start_time'])
372 tourney_map['register_time'] = int(tourney_map.get('register_time', 0))
373 tourney = PokerTournament(dirs = self.dirs, **tourney_map)
374 tourney.serial = tourney_serial
375 tourney.verbose = self.verbose
376 tourney.schedule_serial = schedule_serial
377 tourney.currency_serial = tourney_map['currency_serial']
378 tourney.bailor_serial = tourney_map['bailor_serial']
379 tourney.player_timeout = int(tourney_map['player_timeout'])
380 tourney.callback_new_state = self.tourneyNewState
381 tourney.callback_create_game = self.tourneyCreateTable
382 tourney.callback_game_filled = self.tourneyGameFilled
383 tourney.callback_destroy_game = self.tourneyDestroyGame
384 tourney.callback_move_player = self.tourneyMovePlayer
385 tourney.callback_remove_player = self.tourneyRemovePlayer
386 tourney.callback_cancel = self.tourneyCancel
387 if not self.schedule2tourneys.has_key(schedule_serial):
388 self.schedule2tourneys[schedule_serial] = []
389 self.schedule2tourneys[schedule_serial].append(tourney)
390 self.tourneys[tourney.serial] = tourney
391 return tourney
392
393 def deleteTourney(self, tourney):
394 if self.verbose > 2: print "deleteTourney: %d" % tourney.serial
395 self.schedule2tourneys[tourney.schedule_serial].remove(tourney)
396 if len(self.schedule2tourneys[tourney.schedule_serial]) <= 0:
397 del self.schedule2tourneys[tourney.schedule_serial]
398 del self.tourneys[tourney.serial]
399
400 def tourneyNewState(self, tourney):
401 cursor = self.db.cursor()
402 updates = [ "state = '" + tourney.state + "'" ]
403 if tourney.state == TOURNAMENT_STATE_RUNNING:
404 updates.append("start_time = %d" % tourney.start_time)
405 sql = "update tourneys set " + ", ".join(updates) + " where serial = " + str(tourney.serial)
406 if self.verbose > 4: print "tourneyNewState: " + sql
407 cursor.execute(sql)
408 if cursor.rowcount != 1: print " *ERROR* modified %d rows (expected 1): %s " % ( cursor.rowcount, sql )
409 cursor.close()
410
411 def tourneyEndTurn(self, tourney, game_id):
412 if not tourney.endTurn(game_id):
413 self.tourneyFinished(tourney)
414
415 def tourneyFinished(self, tourney):
416 prizes = tourney.prizes()
417 winners = tourney.winners[:len(prizes)]
418 cursor = self.db.cursor()
419 #
420 # Guaranteed prize pool is withdrawn from a given account if and only if
421 # the buy in of the players is not enough.
422 #
423 bail = tourney.prize_min - ( tourney.buy_in * tourney.registered )
424 if bail > 0:
425 sql = ( "UPDATE user2money SET amount = amount - " + str(bail) + " WHERE " +
426 " user_serial = " + str(tourney.bailor_serial) + " AND " +
427 " currency_serial = " + str(tourney.currency_serial) + " AND " +
428 " amount >= " + str(bail) )
429 if self.verbose > 2: print "tourneyFinished: bailor pays " + sql
430 cursor.execute(sql)
431 if cursor.rowcount != 1:
432 print " *ERROR* tourneyFinished: bailor failed to provide requested money modified %d rows (expected 1): %s " % ( cursor.rowcount, sql )
433 cursor.close()
434 return
435
436 while prizes:
437 prize = prizes.pop(0)
438 serial = winners.pop(0)
439 if prize <= 0:
440 continue
441 sql = "UPDATE user2money SET amount = amount + " + str(prize) + " WHERE user_serial = " + str(serial) + " AND currency_serial = " + str(tourney.currency_serial)
442 if self.verbose > 2: print "tourneyFinished: " + sql
443 cursor.execute(sql)
444 if cursor.rowcount == 0:
445 sql = ( "INSERT INTO user2money (user_serial, currency_serial, amount) VALUES (%d, %d, %d)" %
446 ( serial, tourney.currency_serial, prize ) )
447 if self.verbose > 2: print "tourneyFinished: " + sql
448 cursor.execute(sql)
449
450 if cursor.rowcount != 1:
451 print " *ERROR* tourneyFinished: affected %d rows (expected 1): %s " % ( cursor.rowcount, sql )
452
453 cursor.close()
454
455 def tourneyGameFilled(self, tourney, game):
456 table = self.getTable(game.id)
457 cursor = self.db.cursor()
458 for player in game.playersAll():
459 serial = player.serial
460 player.setUserData(pokeravatar.DEFAULT_PLAYER_USER_DATA.copy())
461 client = self.serial2client.get(serial, None)
462 if client:
463 if self.verbose > 2: print "tourneyGameFilled: player %d connected" % serial
464 table.serial2client[serial] = client
465 else:
466 if self.verbose > 2: print "tourneyGameFilled: player %d disconnected" % serial
467 self.seatPlayer(serial, game.id, game.buyIn())
468
469 if client:
470 client.join(table)
471 sql = "update user2tourney set table_serial = %d where user_serial = %d and tourney_serial = %d" % ( game.id, serial, tourney.serial )
472 if self.verbose > 4: print "tourneyGameFilled: " + sql
473 cursor.execute(sql)
474 if cursor.rowcount != 1: print " *ERROR* modified %d rows (expected 1): %s " % ( cursor.rowcount, sql )
475 cursor.close()
476 table.update()
477
478 def tourneyCreateTable(self, tourney):
479 table = self.createTable(0, { 'name': tourney.name + str(self.table_serial),
480 'variant': tourney.variant,
481 'betting_structure': tourney.betting_structure,
482 'seats': tourney.seats_per_game,
483 'currency_serial': 0,
484 'player_timeout': tourney.player_timeout,
485 'transient': True,
486 'tourney': tourney,
487 })
488 table.timeout_policy = "fold"
489 self.table_serial += 1
490 return table.game
491
492 def tourneyDestroyGame(self, tourney, game):
493 table = self.getTable(game.id)
494 table.destroy()
495
496 def tourneyMovePlayer(self, tourney, from_game_id, to_game_id, serial):
497 from_table = self.getTable(from_game_id)
498 from_table.movePlayer(from_table.serial2client.get(serial, None), serial, to_game_id)
499 cursor = self.db.cursor()
500 sql = "update user2tourney set table_serial = %d where user_serial = %d and tourney_serial = %d" % ( to_game_id, serial, tourney.serial )
501 if self.verbose > 4: print "tourneyMovePlayer: " + sql
502 cursor.execute(sql)
503 if cursor.rowcount != 1: print " *ERROR* modified %d rows (expected 1): %s " % ( cursor.rowcount, sql )
504 cursor.close()
505
506 def tourneyRemovePlayer(self, tourney, game_id, serial):
507 #
508 # Inform the player about its position and prize
509 #
510 prizes = tourney.prizes()
511 rank = tourney.getRank(serial)
512 money = 0
513 players = len(tourney.players)
514 if rank-1 < len(prizes):
515 money = prizes[rank-1]
516
517 client = self.serial2client.get(serial, None)
518 if client:
519 packet = PacketPokerTourneyRank(serial = tourney.serial,
520 game_id = game_id,
521 players = players,
522 rank = rank,
523 money = money)
524 client.sendPacketVerbose(packet)
525 table = self.getTable(game_id)
526 table.kickPlayer(serial)
527 cursor = self.db.cursor()
528 sql = "update user2tourney set rank = %d, table_serial = -1 where user_serial = %d and tourney_serial = %d" % ( tourney.getRank(serial), serial, tourney.serial )
529 if self.verbose > 4: print "tourneyRemovePlayer: " + sql
530 cursor.execute(sql)
531 if cursor.rowcount != 1: print " *ERROR* modified %d rows (expected 1): %s " % ( cursor.rowcount, sql )
532 cursor.close()
533
534 def tourneyPlayersList(self, tourney_serial):
535 if not self.tourneys.has_key(tourney_serial):
536 return PacketError(other_type = PACKET_POKER_TOURNEY_REGISTER,
537 code = PacketPokerTourneyRegister.DOES_NOT_EXIST,
538 message = "Tournament %d does not exist" % tourney_serial)
539 tourney = self.tourneys[tourney_serial]
540 players = map(lambda serial: ( self.getName(serial), -1, 0 ), tourney.players)
541 return PacketPokerTourneyPlayersList(serial = tourney_serial,
542 players = players)
543
544 def tourneyStats(self):
545 players = reduce(operator.add, map(lambda tourney: tourney.registered, self.tourneys.values()))
546 scheduled = filter(lambda schedule: schedule['respawn'] == 'n', self.tourneys_schedule.values())
547 return ( players, len(self.tourneys) + len(scheduled) )
548
549 def tourneySelect(self, string):
550 tourneys = filter(lambda schedule: schedule['respawn'] == 'n', self.tourneys_schedule.values()) + map(lambda tourney: tourney.__dict__, self.tourneys.values() )
551 criterion = split(string, "\t")
552 if string == '':
553 return tourneys
554 elif len(criterion) > 1:
555 ( currency_serial, type ) = criterion
556 sit_n_go = type == 'sit_n_go' and 'y' or 'n'
557 if currency_serial:
558 currency_serial = int(currency_serial)
559 return filter(lambda tourney: tourney['currency_serial'] == currency_serial and tourney['sit_n_go'] == sit_n_go, tourneys)
560 else:
561 return filter(lambda tourney: tourney['sit_n_go'] == sit_n_go, tourneys)
562 else:
563 return filter(lambda tourney: tourney['name'] == string, tourneys)
564
565 def tourneyRegister(self, packet):
566 serial = packet.serial
567 tourney_serial = packet.game_id
568 client = self.serial2client.get(serial, None)
569
570 if not self.tourneys.has_key(tourney_serial):
571 error = PacketError(other_type = PACKET_POKER_TOURNEY_REGISTER,
572 code = PacketPokerTourneyRegister.DOES_NOT_EXIST,
573 message = "Tournament %d does not exist" % tourney_serial)
574 print error
575 if client: client.sendPacketVerbose(error)
576 return False
577 tourney = self.tourneys[tourney_serial]
578
579 if tourney.isRegistered(serial):
580 error = PacketError(other_type = PACKET_POKER_TOURNEY_REGISTER,
581 code = PacketPokerTourneyRegister.ALREADY_REGISTERED,
582 message = "Player %d already registered in tournament %d " % ( serial, tourney_serial ) )
583 print error
584 if client: client.sendPacketVerbose(error)
585 return False
586
587 if not tourney.canRegister(serial):
588 error = PacketError(other_type = PACKET_POKER_TOURNEY_REGISTER,
589 code = PacketPokerTourneyRegister.REGISTRATION_REFUSED,
590 message = "Registration refused in tournament %d " % tourney_serial)
591 print error
592 if client: client.sendPacketVerbose(error)
593 return False
594
595 cursor = self.db.cursor()
596 #
597 # Buy in
598 #
599 currency_serial = tourney.currency_serial
600 withdraw = tourney.buy_in + tourney.rake
601 if withdraw > 0:
602 sql = ( "UPDATE user2money SET amount = amount - " + str(withdraw) +
603 " WHERE user_serial = " + str(serial) + " AND " +
604 " currency_serial = " + str(currency_serial) + " AND " +
605 " amount >= " + str(withdraw)
606 )
607 if self.verbose > 1:
608 print "tourneyRegister: %s" % sql
609 cursor.execute(sql)
610 if cursor.rowcount == 0:
611 error = PacketError(other_type = PACKET_POKER_TOURNEY_REGISTER,
612 code = PacketPokerTourneyRegister.NOT_ENOUGH_MONEY,
613 message = "Not enough money to enter the tournament %d" % tourney_serial)
614 if client: client.sendPacketVerbose(error)
615 print error
616 return False
617 if cursor.rowcount != 1:
618 print " *ERROR* modified %d rows (expected 1): %s " % ( cursor.rowcount, sql )
619 if client:
620 client.sendPacketVerbose(PacketError(other_type = PACKET_POKER_TOURNEY_REGISTER,
621 code = PacketPokerTourneyRegister.SERVER_ERROR,
622 message = "Server error"))
623 return False
624 #
625 # Register
626 #
627 sql = "INSERT INTO user2tourney (user_serial, tourney_serial) VALUES (%d, %d)" % ( serial, tourney_serial )
628 if self.verbose > 4: print "tourneyRegister: " + sql
629 cursor.execute(sql)
630 if cursor.rowcount != 1:
631 print " *ERROR* insert %d rows (expected 1): %s " % ( cursor.rowcount, sql )
632 cursor.close()
633 if client:
634 client.sendPacketVerbose(PacketError(other_type = PACKET_POKER_TOURNEY_REGISTER,
635 code = PacketPokerTourneyRegister.SERVER_ERROR,
636 message = "Server error"))
637 return False
638 cursor.close()
639
640 # notify success
641 if client: client.sendPacketVerbose(packet)
642 tourney.register(serial)
643 return True
644
645 def tourneyUnregister(self, packet):
646 serial = packet.serial
647 tourney_serial = packet.game_id
648 if not self.tourneys.has_key(tourney_serial):
649 return PacketError(other_type = PACKET_POKER_TOURNEY_UNREGISTER,
650 code = PacketPokerTourneyUnregister.DOES_NOT_EXIST,
651 message = "Tournament %d does not exist" % tourney_serial)
652 tourney = self.tourneys[tourney_serial]
653
654 if not tourney.isRegistered(serial):
655 return PacketError(other_type = PACKET_POKER_TOURNEY_UNREGISTER,
656 code = PacketPokerTourneyUnregister.NOT_REGISTERED,
657 message = "Player %d is not registered in tournament %d " % ( serial, tourney_serial ) )
658
659 if not tourney.canUnregister(serial):
660 return PacketError(other_type = PACKET_POKER_TOURNEY_UNREGISTER,
661 code = PacketPokerTourneyUnregister.TOO_LATE,
662 message = "It is too late to unregister player %d from tournament %d " % ( serial, tourney_serial ) )
663
664 cursor = self.db.cursor()
665 #
666 # Refund buy in
667 #
668 currency_serial = tourney.currency_serial
669 withdraw = tourney.buy_in + tourney.rake
670 if withdraw > 0:
671 sql = ( "UPDATE user2money SET amount = amount + " + str(withdraw) +
672 " WHERE user_serial = " + str(serial) + " AND " +
673 " currency_serial = " + str(currency_serial) )
674 if self.verbose > 1:
675 print "tourneyUnregister: %s" % sql
676 cursor.execute(sql)
677 if cursor.rowcount != 1:
678 print " *ERROR* modified %d rows (expected 1): %s " % ( cursor.rowcount, sql )
679 return PacketError(other_type = PACKET_POKER_TOURNEY_UNREGISTER,
680 code = PacketPokerTourneyUnregister.SERVER_ERROR,
681 message = "Server error")
682 #
683 # Unregister
684 #
685 sql = "delete from user2tourney where user_serial = %d and tourney_serial = %d" % ( serial, tourney_serial )
686 if self.verbose > 4: print "tourneyUnregister: " + sql
687 cursor.execute(sql)
688 if cursor.rowcount != 1:
689 print " *ERROR* insert %d rows (expected 1): %s " % ( cursor.rowcount, sql )
690 cursor.close()
691 return PacketError(other_type = PACKET_POKER_TOURNEY_UNREGISTER,
692 code = PacketPokerTourneyUnregister.SERVER_ERROR,
693 message = "Server error")
694 cursor.close()
695
696 tourney.unregister(serial)
697
698 return packet
699
700 def tourneyCancel(self, tourney):
701 if self.verbose > 1: print "tourneyCancel " + str(tourney.players)
702 for serial in tourney.players:
703 packet = self.tourneyUnregister(PacketPokerTourneyUnregister(game_id = tourney.serial,
704 serial = serial))
705 if packet.type == PACKET_ERROR:
706 print "*ERROR* tourneyCancel: " + str(packet)
707
708 def getHandSerial(self):
709 cursor = self.db.cursor()
710 cursor.execute("insert into hands (description) values ('[]')")
711 #
712 # Accomodate with MySQLdb versions < 1.1
713 #
714 if hasattr(cursor, "lastrowid"):
715 serial = cursor.lastrowid
716 else:
717 serial = cursor.insert_id()
718 cursor.close()
719 return int(serial)
720
721 def getHandHistory(self, hand_serial, serial):
722 history = self.loadHand(hand_serial)
723
724 if not history:
725 return PacketPokerError(game_id = hand_serial,
726 serial = serial,
727 other_type = PACKET_POKER_HAND_HISTORY,
728 code = PacketPokerHandHistory.NOT_FOUND,
729 message = "Hand %d was not found in history of player %d" % ( hand_serial, serial ) )
730
731 (type, level, hand_serial, hands_count, time, variant, betting_structure, player_list, dealer, serial2chips) = history[0]
732
733 if serial not in player_list:
734 return PacketPokerError(game_id = hand_serial,
735 serial = serial,
736 other_type = PACKET_POKER_HAND_HISTORY,
737 code = PacketPokerHandHistory.FORBIDDEN,
738 message = "Player %d did not participate in hand %d" % ( serial, hand_serial ) )
739
740 serial2name = {}
741 for player_serial in player_list:
742 serial2name[player_serial] = self.getName(player_serial)
743 #
744 # Filter out the pocket cards that do not belong to player "serial"
745 #
746 for event in history:
747 if event[0] == "round":
748 (type, name, board, pockets) = event
749 if pockets:
750 for (player_serial, pocket) in pockets.iteritems():
751 if player_serial != serial:
752 pocket.loseNotVisible()
753 elif event[0] == "showdown":
754 (type, board, pockets) = event
755 if pockets:
756 for (player_serial, pocket) in pockets.iteritems():
757 if player_serial != serial:
758 pocket.loseNotVisible()
759
760 return PacketPokerHandHistory(game_id = hand_serial,
761 serial = serial,
762 history = str(history),
763 serial2name = str(serial2name))
764
765 def loadHand(self, hand_serial):
766 cursor = self.db.cursor()
767 sql = ( "select description from hands where serial = " + str(hand_serial) )
768 cursor.execute(sql)
769 if cursor.rowcount != 1:
770 print " *ERROR* loadHand(%d) expected one row got %d" % ( hand_serial, cursor.rowcount )
771 cursor.close()
772 return None
773 (description,) = cursor.fetchone()
774 cursor.close()
775 try:
776 history = eval(description.replace("\r",""))
777 return history
778 except:
779 print " *ERROR* loadHand(%d) eval failed for %s" % ( hand_serial, description )
780 print_exc()
781 return None
782
783 def saveHand(self, description, hand_serial):
784 (type, level, hand_serial, hands_count, time, variant, betting_structure, player_list, dealer, serial2chips) = description[0]
785 cursor = self.db.cursor()
786
787 sql = ( "update hands set " +
788 " description = %s "
789 " where serial = " + str(hand_serial) )
790 if self.verbose > 1:
791 print "saveHand: %s" % ( sql % description )
792 cursor.execute(sql, str(description))
793 if cursor.rowcount != 1 and cursor.rowcount != 0:
794 print " *ERROR* modified %d rows (expected 1 or 0): %s " % ( cursor.rowcount, sql )
795 cursor.close()
796 return
797
798 sql = "insert into user2hand values "
799 sql += ", ".join(map(lambda player_serial: "(%d, %d)" % ( player_serial, hand_serial ), player_list))
800 if self.verbose > 1:
801 print "saveHand: %s" % sql
802 cursor.execute(sql)
803 if cursor.rowcount != len(player_list):
804 print " *ERROR* inserted %d rows (expected exactly %d): %s " % ( cursor.rowcount, len(player_list), sql )
805
806
807 cursor.close()
808
809 def listHands(self, sql_list, sql_total):
810 cursor = self.db.cursor()
811 if self.verbose > 1:
812 print "listHands: " + sql_list + " " + sql_total
813 cursor.execute(sql_list)
814 hands = cursor.fetchall()
815 cursor.execute(sql_total)
816 total = cursor.fetchone()[0]
817 cursor.close()
818 return (total, map(lambda x: x[0], hands))
819
820 def statsTables(self):
821 players = reduce(operator.add, map(lambda table: table.game.allCount(), self.tables))
822 return ( players, len(self.tables) )
823
824 def listTables(self, string, serial):
825 criterion = split(string, "\t")
826 if string == '' or string == 'all':
827 return self.tables
828 elif string == 'my':
829 return filter(lambda table: serial in table.game.serialsAll(), self.tables)
830 elif re.match("^[0-9]+$", string):
831 return filter(lambda table: table.currency_serial == int(string), self.tables)
832 elif len(criterion) > 1:
833 ( currency_serial, variant ) = criterion
834 if currency_serial:
835 currency_serial = int(currency_serial)
836 return filter(lambda table: table.game.variant == variant and table.currency_serial == currency_serial, self.tables)
837 else:
838 return filter(lambda table: table.game.variant == variant, self.tables)
839 else:
840 return filter(lambda table: table.game.name == string, self.tables)
841
842 def cleanUp(self, temporary_users = ''):
843 cursor = self.db.cursor()
844
845 if len(temporary_users) > 2:
846 sql = "delete session_history from session_history, users where session_history.user_serial = users.serial and users.name like '" + temporary_users + "%'"
847 cursor.execute(sql)
848 sql = "delete session from session, users where session.user_serial = users.serial and users.name like '" + temporary_users + "%'"
849 cursor.execute(sql)
850 sql = "delete from users where name like '" + temporary_users + "%'"
851 cursor.execute(sql)
852
853 sql = "insert into session_history ( user_serial, started, ended, ip ) select user_serial, started, %d, ip from session" % time.time()
854 cursor.execute(sql)
855 sql = "delete from session"
856 cursor.execute(sql)
857
858 cursor.close()
859
860 def cleanupTourneys(self):
861 self.tourneys = {}
862 self.schedule2tourneys = {}
863 self.tourneys_schedule = {}
864
865 cursor = self.db.cursor(DictCursor)
866 sql = "SELECT * FROM tourneys WHERE state = 'registering' AND start_time > (%d + 60)" % time.time()
867 if self.verbose > 2: print "cleanupTourneys: " + sql
868 cursor.execute(sql)
869 for x in xrange(cursor.rowcount):
870 row = cursor.fetchone()
871 if self.verbose >= 0: message = "cleanupTourneys: restoring %s(%s) with players" % ( row['name'], row['serial'], )
872 tourney = self.spawnTourneyInCore(row, row['serial'], row['schedule_serial'])
873 cursor1 = self.db.cursor()
874 sql = "SELECT user_serial FROM user2tourney WHERE tourney_serial = " + str(row['serial'])
875 if self.verbose > 2: print "cleanupTourneys: " + sql
876 cursor1.execute(sql)
877 for y in xrange(cursor1.rowcount):
878 (serial,) = cursor1.fetchone()
879 if self.verbose >= 0: message += " " + str(serial)
880 tourney.register(serial)
881
882 cursor1.execute(sql)
883 cursor1.close()
884 if self.verbose >= 0: print message
885 cursor.close()
886
887 def getMoney(self, serial, currency_serial):
888 cursor = self.db.cursor()
889 sql = ( "SELECT amount FROM user2money " +
890 " WHERE user_serial = " + str(serial) + " AND " +
891 " currency_serial = " + str(currency_serial) )
892 if self.verbose: print sql
893 cursor.execute(sql)
894 if cursor.rowcount > 1:
895 print " *ERROR* getMoney(%d) expected one row got %d" % ( serial, cursor.rowcount )
896 cursor.close()
897 return 0
898 elif cursor.rowcount == 1:
899 (money,) = cursor.fetchone()
900 else:
901 money = 0
902 cursor.close()
903 return money
904
905 def cashIn(self, packet):
906 return self.cashier.cashIn(packet)
907
908 def cashOut(self, packet):
909 return self.cashier.cashOut(packet)
910
911 def cashQuery(self, packet):
912 return self.cashier.cashQuery(packet)
913
914 def cashOutCommit(self, packet):
915 count = self.cashier.cashOutCommit(packet)
916 if count in (0, 1):
917 return PacketAck()
918 else:
919 return PacketError(code = PacketPokerCashOutCommit.INVALID_TRANSACTION,
920 message = "transaction " + packet.transaction_id + " affected " + str(count) + " rows instead of zero or one",
921 other_type = PACKET_POKER_CASH_OUT_COMMIT)
922
923 def getPlayerInfo(self, serial):
924 placeholder = PacketPokerPlayerInfo(serial = serial,
925 name = "anonymous",
926 url= "random",
927 outfit = "random")
928 if serial == 0:
929 return placeholder
930
931 cursor = self.db.cursor()
932 sql = ( "select name,skin_url,skin_outfit from users where serial = " + str(serial) )
933 cursor.execute(sql)
934 if cursor.rowcount != 1:
935 print " *ERROR* getPlayerInfo(%d) expected one row got %d" % ( serial, cursor.rowcount )
936 return placeholder
937 (name,skin_url,skin_outfit) = cursor.fetchone()
938 if skin_outfit == None:
939 skin_outfit = "random"
940 cursor.close()
941 return PacketPokerPlayerInfo(serial = serial,
942 name = name,
943 url = skin_url,
944 outfit = skin_outfit)
945
946 def getUserInfo(self, serial):
947 cursor = self.db.cursor(DictCursor)
948
949 sql = ( "SELECT rating,affiliate,email,name FROM users WHERE serial = " + str(serial) )
950 cursor.execute(sql)
951 if cursor.rowcount != 1:
952 print " *ERROR* getUserInfo(%d) expected one row got %d" % ( serial, cursor.rowcount )
953 return PacketPokerUserInfo(serial = serial)
954 row = cursor.fetchone()
955 if row['email'] == None: row['email'] = ""
956
957 packet = PacketPokerUserInfo(serial = serial,
958 name = row['name'],
959 email = row['email'],
960 rating = row['rating'],
961 affiliate = row['affiliate'])
962 sql = ( " SELECT user2money.currency_serial,user2money.amount,user2money.points,CAST(SUM(user2table.bet) + SUM(user2table.money) AS UNSIGNED) AS in_game "
963 " FROM user2money LEFT JOIN (pokertables,user2table) "
964 " ON (user2table.user_serial = user2money.user_serial AND "
965 " user2table.table_serial = pokertables.serial AND "
966 " user2money.currency_serial = pokertables.currency_serial) "
967 " WHERE user2money.user_serial = " + str(serial) + " GROUP BY user2money.currency_serial " )
968 if self.verbose: print sql
969 cursor.execute(sql)
970 for row in cursor:
971 if not row['in_game']: row['in_game'] = 0
972 if not row['points']: row['points'] = 0
973 packet.money[row['currency_serial']] = ( row['amount'], row['in_game'], row['points'] )
974 if self.verbose > 2: print "getUserInfo: " + str(packet)
975 return packet
976
977 def getPersonalInfo(self, serial):
978 user_info = self.getUserInfo(serial)
979 print "getPersonalInfo %s" % str(user_info)
980 packet = PacketPokerPersonalInfo(serial = user_info.serial,
981 name = user_info.name,
982 email = user_info.email,
983 rating = user_info.rating,
984 affiliate = user_info.affiliate,
985 money = user_info.money)
986 cursor = self.db.cursor()
987 sql = ( "SELECT firstname,lastname,addr_street,addr_street2,addr_zip,addr_town,addr_state,addr_country,phone,gender,birthdate FROM users_private WHERE serial = " + str(serial) )
988 cursor.execute(sql)
989 if cursor.rowcount != 1:
990 print " *ERROR* getPersonalInfo(%d) expected one row got %d" % ( serial, cursor.rowcount )
991 return PacketPokerPersonalInfo(serial = serial)
992 (packet.firstname, packet.lastname, packet.addr_street, packet.addr_street2, packet.addr_zip, packet.addr_town, packet.addr_state, packet.addr_country, packet.phone, packet.gender, packet.birthdate) = cursor.fetchone()
993 cursor.close()
994 if not packet.gender: packet.gender = ''
995 if not packet.birthdate: packet.birthdate = ''
996 return packet
997
998 def setPersonalInfo(self, personal_info):
999 cursor = self.db.cursor()
1000 sql = ( "UPDATE users_private SET "
1001 " firstname = '" + personal_info.firstname + "', "
1002 " lastname = '" + personal_info.lastname + "', "
1003 " addr_street = '" + personal_info.addr_street + "', "
1004 " addr_street2 = '" + personal_info.addr_street2 + "', "
1005 " addr_zip = '" + personal_info.addr_zip + "', "
1006 " addr_town = '" + personal_info.addr_town + "', "
1007 " addr_state = '" + personal_info.addr_state + "', "
1008 " addr_country = '" + personal_info.addr_country + "', "
1009 " phone = '" + personal_info.phone + "', "
1010 " gender = '" + personal_info.gender + "', "
1011 " birthdate = '" + personal_info.birthdate + "' "
1012 " WHERE serial = " + str(personal_info.serial) )
1013 if self.verbose > 1:
1014 print "setPersonalInfo: %s" % sql
1015 cursor.execute(sql)
1016 if cursor.rowcount != 1 and cursor.rowcount != 0:
1017 print " *ERROR* setPersonalInfo: modified %d rows (expected 1 or 0): %s " % ( cursor.rowcount, sql )
1018 return False
1019 else:
1020 return True
1021
1022 def setAccount(self, packet):
1023 #
1024 # name constraints check
1025 #
1026 status = checkName(packet.name)
1027 if not status[0]:
1028 return PacketError(code = status[1],
1029 message = status[2],
1030 other_type = packet.type)
1031 #
1032 # Look for user
1033 #
1034 cursor = self.db.cursor()
1035 cursor.execute("select serial from users where name = '%s'" % packet.name)
1036 numrows = int(cursor.rowcount)
1037 #
1038 # password constraints check
1039 #
1040 if ( numrows == 0 or ( numrows > 0 and packet.password != "" )):
1041 status = checkPassword(packet.password)
1042 if not status[0]:
1043 return PacketError(code = status[1],
1044 message = status[2],
1045 other_type = packet.type)
1046 #
1047 # email constraints check
1048 #
1049 email_regexp = ".*.@.*\..*$"
1050 if not re.match(email_regexp, packet.email):
1051 return PacketError(code = PacketPokerSetAccount.INVALID_EMAIL,
1052 message = "email %s does not match %s " % ( packet.email, email_regexp ),
1053 other_type = packet.type)
1054 if numrows == 0:
1055 cursor.execute("select serial from users where email = '%s' " % packet.email)
1056 numrows = int(cursor.rowcount)
1057 if numrows > 0:
1058 return PacketError(code = PacketPokerSetAccount.EMAIL_ALREADY_EXISTS,
1059 message = "there already is another account with the email %s" % packet.email,
1060 other_type = packet.type)
1061 #
1062 # User does not exists, create it
1063 #
1064 sql = "INSERT INTO users (created, name, password, email, affiliate) values (%d, '%s', '%s', '%s', '%d')" % (time.time(), packet.name, packet.password, packet.email, packet.affiliate)
1065 cursor.execute(sql)
1066 if cursor.rowcount != 1:
1067 print " *ERROR* setAccount: insert %d rows (expected 1): %s " % ( cursor.rowcount, sql )
1068 return PacketError(code = PacketPokerSetAccount.SERVER_ERROR,
1069 message = "inserted %d rows (expected 1)" % cursor.rowcount,
1070 other_type = packet.type)
1071 #
1072 # Accomodate for MySQLdb versions < 1.1
1073 #
1074 if hasattr(cursor, "lastrowid"):
1075 packet.serial = cursor.lastrowid
1076 else:
1077 packet.serial = cursor.insert_id()
1078 cursor.execute("insert into users_private (serial) values ('%d')" % packet.serial)
1079 if int(cursor.rowcount) == 0:
1080 print " *ERROR* setAccount: unable to create user_private entry for serial %d" % packet.serial
1081 return PacketError(code = PacketPokerSetAccount.SERVER_ERROR,
1082 message = "unable to create user_private entry for serial %d" % packet.serial,
1083 other_type = packet.type)
1084 else:
1085 #
1086 # User exists, update name, password and email
1087 #
1088 (serial,) = cursor.fetchone()
1089 if serial != packet.serial:
1090 return PacketError(code = PacketPokerSetAccount.NAME_ALREADY_EXISTS,
1091 message = "user name %s already exists" % packet.name,
1092 other_type = packet.type)
1093 cursor.execute("select serial from users where email = '%s' and serial != %d" % ( packet.email, serial ))
1094 numrows = int(cursor.rowcount)
1095 if numrows > 0:
1096 return PacketError(code = PacketPokerSetAccount.EMAIL_ALREADY_EXISTS,
1097 message = "there already is another account with the email %s" % packet.email,
1098 other_type = packet.type)
1099 set_password = packet.password and ", password = '" + packet.password + "' " or ""
1100 sql = ( "update users set "
1101 " name = '" + packet.name + "', "
1102 " email = '" + packet.email + "' " +
1103 set_password +
1104 " where serial = " + str(packet.serial) )
1105 if self.verbose > 1:
1106 print "setAccount: %s" % sql
1107 cursor.execute(sql)
1108 if cursor.rowcount != 1 and cursor.rowcount != 0:
1109 print " *ERROR* setAccount: modified %d rows (expected 1 or 0): %s " % ( cursor.rowcount, sql )
1110 return PacketError(code = PacketPokerSetAccount.SERVER_ERROR,
1111 message = "modified %d rows (expected 1 or 0)" % cursor.rowcount,
1112 other_type = packet.type)
1113 #
1114 # Set personal information
1115 #
1116 if not self.setPersonalInfo(packet):
1117 return PacketError(code = PacketPokerSetAccount.SERVER_ERROR,
1118 message = "unable to set personal information",
1119 other_type = packet.type)
1120 return self.getPersonalInfo(packet.serial)
1121
1122 def setPlayerInfo(self, player_info):
1123 cursor = self.db.cursor()
1124 sql = ( "update users set "
1125 " name = '" + player_info.name + "', "
1126 " skin_url = '" + player_info.url + "', "
1127 " skin_outfit = '" + player_info.outfit + "' "
1128 " where serial = " + str(player_info.serial) )
1129 if self.verbose > 1:
1130 print "setPlayerInfo: %s" % sql
1131 cursor.execute(sql)
1132 if cursor.rowcount != 1 and cursor.rowcount != 0:
1133 print " *ERROR* setPlayerInfo: modified %d rows (expected 1 or 0): %s " % ( cursor.rowcount, sql )
1134 return False
1135 return True
1136
1137
1138 def getPlayerImage(self, serial):
1139 placeholder = PacketPokerPlayerImage(serial = serial)
1140
1141 if serial == 0:
1142 return placeholder
1143
1144 cursor = self.db.cursor()
1145 sql = ( "select skin_image,skin_image_type from users where serial = " + str(serial) )
1146 cursor.execute(sql)
1147 if cursor.rowcount != 1:
1148 print " *ERROR* getPlayerImage(%d) expected one row got %d" % ( serial, cursor.rowcount )
1149 return placeholder
1150 (skin_image, skin_image_type) = cursor.fetchone()
1151 if skin_image == None:
1152 skin_image = ""
1153 cursor.close()
1154 return PacketPokerPlayerImage(serial = serial,
1155 image = skin_image,
1156 image_type = skin_image_type)
1157
1158 def setPlayerImage(self, player_image):
1159 cursor = self.db.cursor()
1160 sql = ( "update users set "
1161 " skin_image = '" + player_image.image + "', "
1162 " skin_image_type = '" + player_image.image_type + "' "
1163 " where serial = " + str(player_image.serial) )
1164 if self.verbose > 1:
1165 print "setPlayerInfo: %s" % sql
1166 cursor.execute(sql)
1167 if cursor.rowcount != 1 and cursor.rowcount != 0:
1168 print " *ERROR* setPlayerImage: modified %d rows (expected 1 or 0): %s " % ( cursor.rowcount, sql )
1169 return False
1170 return True
1171
1172 def getName(self, serial):
1173 if serial == 0:
1174 return "anonymous"
1175
1176 cursor = self.db.cursor()
1177 sql = ( "select name from users where serial = " + str(serial) )
1178 cursor.execute(sql)
1179 if cursor.rowcount != 1:
1180 print " *ERROR* getName(%d) expected one row got %d" % ( serial, cursor.rowcount )
1181 return "UNKNOWN"
1182 (name,) = cursor.fetchone()
1183 cursor.close()
1184 return name
1185
1186 def buyInPlayer(self, serial, table_id, currency_serial, amount):
1187 # unaccounted money is delivered regardless
1188 if not currency_serial: return amount
1189
1190 withdraw = min(self.getMoney(serial, currency_serial), amount)
1191 cursor = self.db.cursor()
1192 sql = ( "UPDATE user2money,user2table SET "
1193 " user2table.money = user2table.money + " + str(withdraw) + ", "
1194 " user2money.amount = user2money.amount - " + str(withdraw) + " "
1195 " WHERE user2money.user_serial = " + str(serial) + " AND "
1196 " user2money.currency_serial = " + str(currency_serial) + " AND "
1197 " user2table.user_serial = " + str(serial) + " AND "
1198 " user2table.table_serial = " + str(table_id) )
1199 if self.verbose > 1:
1200 print "buyInPlayer: %s" % sql
1201 cursor.execute(sql)
1202 if cursor.rowcount != 0 and cursor.rowcount != 2:
1203 print " *ERROR* modified %d rows (expected 0 or 2): %s " % ( cursor.rowcount, sql )
1204 return withdraw
1205
1206 def seatPlayer(self, serial, table_id, amount):
1207 status = True
1208 cursor = self.db.cursor()
1209 sql = ( "INSERT user2table ( user_serial, table_serial, money) VALUES "
1210 " ( " + str(serial) + ", " + str(table_id) + ", " + str(amount) + " )" )
1211 if self.verbose > 1:
1212 print "seatPlayer: %s" % sql
1213 cursor.execute(sql)
1214 if cursor.rowcount != 1:
1215 print " *ERROR* inserted %d rows (expected 1): %s " % ( cursor.rowcount, sql )
1216 status = False
1217 cursor.close()
1218 return status
1219
1220 def movePlayer(self, serial, from_table_id, to_table_id):
1221 money = -1
1222 cursor = self.db.cursor()
1223 sql = ( "SELECT money FROM user2table "
1224 " WHERE user_serial = " + str(serial) + " AND "
1225 " table_serial = " + str(from_table_id) )
1226 cursor.execute(sql)
1227 if cursor.rowcount != 1:
1228 print " *ERROR* movePlayer(%d) expected one row got %d" % ( serial, cursor.rowcount )
1229 (money,) = cursor.fetchone()
1230 cursor.close()
1231
1232 if money > 0:
1233 cursor = self.db.cursor()
1234 sql = ( "update user2table "
1235 " set table_serial = " + str(to_table_id) +
1236 " where user_serial = " + str(serial) + " and"
1237 " table_serial = " + str(from_table_id) )
1238 if self.verbose > 1:
1239 print "movePlayer: %s" % sql
1240 cursor.execute(sql)
1241 if cursor.rowcount != 1:
1242 print " *ERROR* modified %d rows (expected 1): %s " % ( cursor.rowcount, sql )
1243 money = -1
1244 cursor.close()
1245
1246 # HACK CHECK
1247# cursor = self.db.cursor()
1248# sql = ( "select sum(money), sum(bet) from user2table" )
1249# cursor.execute(sql)
1250# (total_money,bet) = cursor.fetchone()
1251# if total_money + bet != 120000:
1252# print "BUG(6) %d" % (total_money + bet)
1253# os.abort()
1254# cursor.close()
1255 # END HACK CHECK
1256
1257 return money
1258
1259 def leavePlayer(self, serial, table_id, currency_serial):
1260 status = True
1261 cursor = self.db.cursor()
1262 if currency_serial != '':
1263 sql = ( "UPDATE user2money,user2table,pokertables SET " +
1264 " user2money.amount = user2money.amount + user2table.money + user2table.bet " +
1265 " WHERE user2money.user_serial = user2table.user_serial AND " +
1266 " user2money.currency_serial = pokertables.currency_serial AND " +
1267 " pokertables.serial = " + str(table_id) + " AND " +
1268 " user2table.table_serial = " + str(table_id) + " AND " +
1269 " user2table.user_serial = " + str(serial) )
1270 if self.verbose > 1:
1271 print "leavePlayer %s" % sql
1272 cursor.execute(sql)
1273 if cursor.rowcount > 1:
1274 print " *ERROR* modified %d rows (expected 0 or 1): %s " % ( cursor.rowcount, sql )
1275 status = False
1276 sql = ( "delete from user2table "
1277 " where user_serial = " + str(serial) + " and "
1278 " table_serial = " + str(table_id) )
1279 if self.verbose > 1:
1280 print "leavePlayer %s" % sql
1281 cursor.execute(sql)
1282 if cursor.rowcount != 1:
1283 print " *ERROR* modified %d rows (expected 1): %s " % ( cursor.rowcount, sql )
1284 status = False
1285 cursor.close()
1286 return status
1287
1288 def updatePlayerRake(self, currency_serial, serial, amount):
1289 if amount == 0:
1290 return True
1291 status = True
1292 cursor = self.db.cursor()
1293 sql = ( "UPDATE user2money SET "
1294 " rake = rake + " + str(amount) + ", "
1295 " points = points + " + str(amount) + " "
1296 " WHERE user_serial = " + str(serial) + " AND "
1297 " currency_serial = " + str(currency_serial) )
1298 if self.verbose > 1:
1299 print "updatePlayerRake: %s" % sql
1300 cursor.execute(sql)
1301 if cursor.rowcount != 1:
1302 print " *ERROR* modified %d rows (expected 1): %s " % ( cursor.rowcount, sql )
1303 status = False
1304 cursor.close()
1305
1306 def updatePlayerMoney(self, serial, table_id, amount):
1307 if amount == 0:
1308 return True
1309 status = True
1310 cursor = self.db.cursor()
1311 sql = ( "UPDATE user2table SET "
1312 " money = money + " + str(amount) + ", "
1313 " bet = bet - " + str(amount) +
1314 " WHERE user_serial = " + str(serial) + " AND "
1315 " table_serial = " + str(table_id) )
1316 if self.verbose > 1:
1317 print "updatePlayerMoney: %s" % sql
1318 cursor.execute(sql)
1319 if cursor.rowcount != 1:
1320 print " *ERROR* modified %d rows (expected 1): %s " % ( cursor.rowcount, sql )
1321 status = False
1322 cursor.close()
1323
1324# # HACK CHECK
1325# cursor = self.db.cursor()
1326# sql = ( "select sum(money), sum(bet) from user2table" )
1327# cursor.execute(sql)
1328# (money,bet) = cursor.fetchone()
1329# if money + bet != 120000:
1330# print "BUG(4) %d" % (money + bet)
1331# os.abort()
1332# cursor.close()
1333
1334# cursor = self.db.cursor()
1335# sql = ( "select user_serial,table_serial,money from user2table where money < 0" )
1336# cursor.execute(sql)
1337# if cursor.rowcount >= 1:
1338# (user_serial, table_serial, money) = cursor.fetchone()
1339# print "BUG(11) %d/%d/%d" % (user_serial, table_serial, money)
1340# os.abort()
1341# cursor.close()
1342# # END HACK CHECK
1343
1344 return status
1345
1346 def tableMoneyAndBet(self, table_id):
1347 cursor = self.db.cursor()
1348 sql = ( "SELECT sum(money), sum(bet) FROM user2table WHERE table_serial = " + str(table_id) )
1349 cursor.execute(sql)
1350 (money, bet) = cursor.fetchone()
1351 cursor.close()
1352 if not money: money = 0
1353 elif type(money) == StringType: money = int(money)
1354 if not bet: bet = 0
1355 elif type(bet) == StringType: bet = int(bet)
1356 return (money, bet)
1357
1358 def destroyTable(self, table_id):
1359
1360# # HACK CHECK
1361# cursor = self.db.cursor()
1362# sql = ( "select * from user2table where money != 0 and bet != 0 and table_serial = " + str(table_id) )
1363# cursor.execute(sql)
1364# if cursor.rowcount != 0:
1365# print "BUG(10)"
1366# os.abort()
1367# cursor.close()
1368# # END HACK CHECK
1369
1370 cursor = self.db.cursor()
1371 sql = ( "delete from user2table "
1372 " where table_serial = " + str(table_id) )
1373 if self.verbose > 1:
1374 print "destroy: %s" % sql
1375 cursor.execute(sql)
1376
1377# def setRating(self, winners, serials):
1378# url = self.settings.headerGet("/server/@rating")
1379# if url == "":
1380# return
1381
1382# params = []
1383# for first in range(0, len(serials) - 1):
1384# for second in range(first + 1, len(serials)):
1385# first_wins = serials[first] in winners
1386# second_wins = serials[second] in winners
1387# if first_wins or second_wins:
1388# param = "a=%d&b=%d&c=" % ( serials[first], serials[second] )
1389# if first_wins and second_wins:
1390# param += "2"
1391# elif first_wins:
1392# param += "0"
1393# else:
1394# param += "1"
1395# params.append(param)
1396
1397# params = join(params, '&')
1398# if self.verbose > 2:
1399# print "setRating: url = %s" % url + params
1400# content = loadURL(url + params)
1401# if self.verbose > 2:
1402# print "setRating: %s" % content
1403
1404 def resetBet(self, table_id):
1405 status = True
1406 cursor = self.db.cursor()
1407 sql = ( "update user2table set bet = 0 "
1408 " where table_serial = " + str(table_id) )
1409 if self.verbose > 1:
1410 print "resetBet: %s" % sql
1411 cursor.execute(sql)
1412 cursor.close()
1413
1414# # HACK CHECK
1415# cursor = self.db.cursor()
1416# sql = ( "select sum(money), sum(bet) from user2table" )
1417# cursor.execute(sql)
1418# (money,bet) = cursor.fetchone()
1419# if money + bet != 120000:
1420# print "BUG(2) %d" % (money + bet)
1421# os.abort()
1422# cursor.close()
1423# # END HACK CHECK
1424
1425 return status
1426
1427 def getTable(self, game_id):
1428 for table in self.tables:
1429 if game_id == table.game.id:
1430 game = table.game
1431 return table
1432 return False
1433
1434 def createTable(self, owner, description):
1435 #
1436 # Do not create two tables by the same name
1437 #
1438 if filter(lambda table: table.game.name == description["name"], self.tables):
1439 print "*ERROR* will not create two tables by the same name %s" % description["name"]
1440 return False
1441
1442 id = self.table_serial
1443 table = PokerTable(self, id, description)
1444 table.owner = owner
1445
1446 cursor = self.db.cursor()
1447 sql = ( "INSERT pokertables ( serial, name, currency_serial ) VALUES "
1448 " ( " + str(id) + ", \"" + description["name"] + "\", " + str(description["currency_serial"]) + " ) " )
1449 if self.verbose > 1:
1450 print "createTable: %s" % sql
1451 cursor.execute(sql)
1452 if cursor.rowcount != 1:
1453 print " *ERROR* inserted %d rows (expected 1): %s " % ( cursor.rowcount, sql )
1454 cursor.close()
1455
1456 self.tables.append(table)
1457 self.table_serial += 1
1458
1459 if self.verbose:
1460 print "table created : %s" % table.game.name
1461
1462 return table
1463
1464 def cleanupCrashedTables(self):
1465 cursor = self.db.cursor()
1466
1467 sql = ( "select user_serial,table_serial,currency_serial from pokertables,user2table where user2table.table_serial = pokertables.serial " )
1468 cursor.execute(sql)
1469 if cursor.rowcount > 0 and self.verbose > 1:
1470 print "cleanupCrashedTables found %d players" % cursor.rowcount
1471 for i in xrange(cursor.rowcount):
1472 (user_serial, table_serial, currency_serial) = cursor.fetchone()
1473 self.leavePlayer(user_serial, table_serial, currenc