Merge branch 'master' of git://git.assembla.com/fpdboz

This commit is contained in:
grindi 2009-08-12 19:58:29 +04:00
commit 25923b02d1
9 changed files with 3165 additions and 3138 deletions

View File

@ -26,6 +26,12 @@ from HandHistoryConverter import *
# Class for converting Absolute HH format. # Class for converting Absolute HH format.
class Absolute(HandHistoryConverter): class Absolute(HandHistoryConverter):
# Class Variables
sitename = "Absolute"
filetype = "text"
codepage = "cp1252"
siteid = 8
# Static regexes # Static regexes
re_SplitHands = re.compile(r"\n\n\n+") re_SplitHands = re.compile(r"\n\n\n+")
@ -48,24 +54,6 @@ class Absolute(HandHistoryConverter):
# re_Board = re.compile(ur"\[ (?P<CARDS>.+) \]") # re_Board = re.compile(ur"\[ (?P<CARDS>.+) \]")
def __init__(self, in_path = '-', out_path = '-', follow = False, autostart=True, debugging=False, index=0):
"""\
in_path (default '-' = sys.stdin)
out_path (default '-' = sys.stdout)
follow : whether to tail -f the input
autostart: whether to run the thread (or you can call start() yourself)
debugging: if False, pass on partially supported game types. If true, have a go and error..."""
#print "DEBUG: XXXXXXXXXXXXXXX"
HandHistoryConverter.__init__(self, in_path, out_path, sitename="Absolute", follow=follow, index=index)
logging.info("Initialising Absolute converter class")
self.filetype = "text"
self.codepage = "cp1252"
self.siteId = 8 # Needs to match id entry in Sites database
self.debugging = debugging
if autostart:
self.start()
# otherwise you need to call start yourself.
def compilePlayerRegexs(self, hand): def compilePlayerRegexs(self, hand):
players = set([player[1] for player in hand.players]) players = set([player[1] for player in hand.players])
if not players <= self.compiledPlayers: # x <= y means 'x is subset of y' if not players <= self.compiledPlayers: # x <= y means 'x is subset of y'

View File

@ -1150,11 +1150,16 @@ class Database:
boardcard2, boardcard2,
boardcard3, boardcard3,
boardcard4, boardcard4,
boardcard5 boardcard5,
street1Pot,
street2Pot,
street3Pot,
street4Pot,
showdownPot
) )
VALUES VALUES
(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s,
%s, %s)""" %s, %s, %s, %s, %s, %s, %s)"""
#--- texture, #--- texture,
#-- playersVpi, #-- playersVpi,
#-- playersAtStreet1, #-- playersAtStreet1,
@ -1167,11 +1172,6 @@ class Database:
#-- street2Raises, #-- street2Raises,
#-- street3Raises, #-- street3Raises,
#-- street4Raises, #-- street4Raises,
#-- street1Pot,
#-- street2Pot,
#-- street3Pot,
#-- street4Pot,
#-- showdownPot
#-- seats, #-- seats,
q = q.replace('%s', self.sql.query['placeholder']) q = q.replace('%s', self.sql.query['placeholder'])
@ -1190,7 +1190,7 @@ class Database:
p['boardcard2'], p['boardcard2'],
p['boardcard3'], p['boardcard3'],
p['boardcard4'], p['boardcard4'],
p['boardcard5']) p['boardcard5'],
# hudCache['playersVpi'], # hudCache['playersVpi'],
# hudCache['playersAtStreet1'], # hudCache['playersAtStreet1'],
# hudCache['playersAtStreet2'], # hudCache['playersAtStreet2'],
@ -1202,12 +1202,12 @@ class Database:
# hudCache['street2Raises'], # hudCache['street2Raises'],
# hudCache['street3Raises'], # hudCache['street3Raises'],
# hudCache['street4Raises'], # hudCache['street4Raises'],
# hudCache['street1Pot'], p['street1Pot'],
# hudCache['street2Pot'], p['street2Pot'],
# hudCache['street3Pot'], p['street3Pot'],
# hudCache['street4Pot'], p['street4Pot'],
# hudCache['showdownPot'] p['showdownPot']
) ))
#return getLastInsertId(backend, conn, cursor) #return getLastInsertId(backend, conn, cursor)
# def storeHand # def storeHand

View File

@ -22,7 +22,6 @@ import gtk
import os import os
import fpdb_simple import fpdb_simple
import fpdb_import import fpdb_import
import fpdb_db import fpdb_db

View File

@ -203,11 +203,6 @@ db: a connected fpdb_db object"""
hh['tableName'] = self.tablename hh['tableName'] = self.tablename
hh['maxSeats'] = self.maxseats hh['maxSeats'] = self.maxseats
hh['seats'] = len(sqlids) hh['seats'] = len(sqlids)
# boardcard1 smallint, /* 0=none, 1-13=2-Ah 14-26=2-Ad 27-39=2-Ac 40-52=2-As */
# boardcard2 smallint,
# boardcard3 smallint,
# boardcard4 smallint,
# boardcard5 smallint,
# Flop turn and river may all be empty - add (likely) too many elements and trim with range # Flop turn and river may all be empty - add (likely) too many elements and trim with range
boardcards = self.board['FLOP'] + self.board['TURN'] + self.board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x'] boardcards = self.board['FLOP'] + self.board['TURN'] + self.board['RIVER'] + [u'0x', u'0x', u'0x', u'0x', u'0x']
cards = [Card.encodeCard(c) for c in boardcards[0:5]] cards = [Card.encodeCard(c) for c in boardcards[0:5]]
@ -217,7 +212,6 @@ db: a connected fpdb_db object"""
hh['boardcard4'] = cards[3] hh['boardcard4'] = cards[3]
hh['boardcard5'] = cards[4] hh['boardcard5'] = cards[4]
print hh
# texture smallint, # texture smallint,
# playersVpi SMALLINT NOT NULL, /* num of players vpi */ # playersVpi SMALLINT NOT NULL, /* num of players vpi */
# Needs to be recorded # Needs to be recorded
@ -241,17 +235,14 @@ db: a connected fpdb_db object"""
# Needs to be recorded # Needs to be recorded
# street4Raises TINYINT NOT NULL, /* num big bets paid to see showdown */ # street4Raises TINYINT NOT NULL, /* num big bets paid to see showdown */
# Needs to be recorded # Needs to be recorded
# street1Pot INT, /* pot size at flop/street4 */
# Needs to be recorded #print "DEBUG: self.getStreetTotals = (%s, %s, %s, %s, %s)" % self.getStreetTotals()
# street2Pot INT, /* pot size at turn/street5 */ #FIXME: Pot size still in decimal, needs to be converted to cents
# Needs to be recorded (hh['street1Pot'], hh['street2Pot'], hh['street3Pot'], hh['street4Pot'], hh['showdownPot']) = self.getStreetTotals()
# street3Pot INT, /* pot size at river/street6 */
# Needs to be recorded
# street4Pot INT, /* pot size at sd/street7 */
# Needs to be recorded
# showdownPot INT, /* pot size at sd/street7 */
# comment TEXT, # comment TEXT,
# commentTs DATETIME # commentTs DATETIME
#print hh
handid = db.storeHand(hh) handid = db.storeHand(hh)
# HandsPlayers - ? ... Do we fix winnings? # HandsPlayers - ? ... Do we fix winnings?
# Tourneys ? # Tourneys ?
@ -489,7 +480,6 @@ Card ranks will be uppercased
board = set([c for s in self.board.values() for c in s]) board = set([c for s in self.board.values() for c in s])
self.addHoleCards(holeandboard.difference(board),player,shown, mucked) self.addHoleCards(holeandboard.difference(board),player,shown, mucked)
def totalPot(self): def totalPot(self):
"""If all bets and blinds have been added, totals up the total pot size""" """If all bets and blinds have been added, totals up the total pot size"""
@ -573,6 +563,9 @@ Map the tuple self.gametype onto the pokerstars string describing it
"""Return a string of the stakes of the current hand.""" """Return a string of the stakes of the current hand."""
return "%s%s/%s%s" % (self.sym, self.sb, self.sym, self.bb) return "%s%s/%s%s" % (self.sym, self.sb, self.sym, self.bb)
def getStreetTotals(self):
pass
def writeGameLine(self): def writeGameLine(self):
"""Return the first HH line for the current hand.""" """Return the first HH line for the current hand."""
gs = "PokerStars Game #%s: " % self.handid gs = "PokerStars Game #%s: " % self.handid
@ -638,6 +631,7 @@ class HoldemOmahaHand(Hand):
for street in self.actionStreets: for street in self.actionStreets:
if self.streets[street]: if self.streets[street]:
hhc.readAction(self, street) hhc.readAction(self, street)
self.pot.markTotal(street)
hhc.readCollectPot(self) hhc.readCollectPot(self)
hhc.readShownCards(self) hhc.readShownCards(self)
self.totalPot() # finalise it (total the pot) self.totalPot() # finalise it (total the pot)
@ -662,6 +656,18 @@ class HoldemOmahaHand(Hand):
else: else:
self.addHoleCards('PREFLOP', player, open=[], closed=cards, shown=shown, mucked=mucked, dealt=dealt) self.addHoleCards('PREFLOP', player, open=[], closed=cards, shown=shown, mucked=mucked, dealt=dealt)
def getStreetTotals(self):
# street1Pot INT, /* pot size at flop/street4 */
# street2Pot INT, /* pot size at turn/street5 */
# street3Pot INT, /* pot size at river/street6 */
# street4Pot INT, /* pot size at sd/street7 */
# showdownPot INT, /* pot size at sd/street7 */
tmp1 = self.pot.getTotalAtStreet('FLOP')
tmp2 = self.pot.getTotalAtStreet('TURN')
tmp3 = self.pot.getTotalAtStreet('RIVER')
tmp4 = 0
tmp5 = 0
return (tmp1,tmp2,tmp3,tmp4,tmp5)
def writeHTMLHand(self, fh=sys.__stdout__): def writeHTMLHand(self, fh=sys.__stdout__):
from nevow import tags as T from nevow import tags as T
@ -886,6 +892,7 @@ class DrawHand(Hand):
for street in self.streetList: for street in self.streetList:
if self.streets[street]: if self.streets[street]:
hhc.readAction(self, street) hhc.readAction(self, street)
self.pot.markTotal(street)
hhc.readCollectPot(self) hhc.readCollectPot(self)
hhc.readShownCards(self) hhc.readShownCards(self)
self.totalPot() # finalise it (total the pot) self.totalPot() # finalise it (total the pot)
@ -946,6 +953,14 @@ class DrawHand(Hand):
act = (player, 'discards', num) act = (player, 'discards', num)
self.actions[street].append(act) self.actions[street].append(act)
def getStreetTotals(self):
# street1Pot INT, /* pot size at flop/street4 */
# street2Pot INT, /* pot size at turn/street5 */
# street3Pot INT, /* pot size at river/street6 */
# street4Pot INT, /* pot size at sd/street7 */
# showdownPot INT, /* pot size at sd/street7 */
return (0,0,0,0,0)
def writeHand(self, fh=sys.__stdout__): def writeHand(self, fh=sys.__stdout__):
# PokerStars format. # PokerStars format.
@ -1053,6 +1068,7 @@ class StudHand(Hand):
if self.streets[street]: if self.streets[street]:
log.debug(street + self.streets[street]) log.debug(street + self.streets[street])
hhc.readAction(self, street) hhc.readAction(self, street)
self.pot.markTotal(street)
hhc.readCollectPot(self) hhc.readCollectPot(self)
hhc.readShownCards(self) # not done yet hhc.readShownCards(self) # not done yet
self.totalPot() # finalise it (total the pot) self.totalPot() # finalise it (total the pot)
@ -1123,6 +1139,14 @@ Add a complete on [street] by [player] to [amountTo]
self.lastBet['THIRD'] = Decimal(bringin) self.lastBet['THIRD'] = Decimal(bringin)
self.pot.addMoney(player, Decimal(bringin)) self.pot.addMoney(player, Decimal(bringin))
def getStreetTotals(self):
# street1Pot INT, /* pot size at flop/street4 */
# street2Pot INT, /* pot size at turn/street5 */
# street3Pot INT, /* pot size at river/street6 */
# street4Pot INT, /* pot size at sd/street7 */
# showdownPot INT, /* pot size at sd/street7 */
return (0,0,0,0,0)
def writeHand(self, fh=sys.__stdout__): def writeHand(self, fh=sys.__stdout__):
# PokerStars format. # PokerStars format.
@ -1281,11 +1305,12 @@ class Pot(object):
def __init__(self): def __init__(self):
self.contenders = set() self.contenders = set()
self.committed = {} self.committed = {}
self.total = None self.streettotals = {}
self.returned = {} self.total = None
self.sym = u'$' # this is the default currency symbol self.returned = {}
self.sym = u'$' # this is the default currency symbol
def setSym(self, sym): def setSym(self, sym):
self.sym = sym self.sym = sym
@ -1302,6 +1327,14 @@ class Pot(object):
self.contenders.add(player) self.contenders.add(player)
self.committed[player] += amount self.committed[player] += amount
def markTotal(self, street):
self.streettotals[street] = sum(self.committed.values())
def getTotalAtStreet(self, street):
if street in self.streettotals:
return self.streettotals[street]
return 0
def end(self): def end(self):
self.total = sum(self.committed.values()) self.total = sum(self.committed.values())

View File

@ -77,9 +77,13 @@ follow : whether to tail -f the input"""
# TODO: out_path should be sanity checked. # TODO: out_path should be sanity checked.
out_dir = os.path.dirname(self.out_path) out_dir = os.path.dirname(self.out_path)
if not os.path.isdir(out_dir) and out_dir != '': if not os.path.isdir(out_dir) and out_dir != '':
logging.info("Creatin directory '%s'" % out_dir) log.info("Creating directory '%s'" % out_dir)
os.makedirs(out_dir) os.makedirs(out_dir)
self.out_fh = codecs.open(self.out_path, 'w', 'cp1252') try:
self.out_fh = codecs.open(self.out_path, 'w', 'cp1252')
log.debug("out_path %s opened as %s" % (self.out_path, self.out_fh))
except:
log.error("out_path %s couldn't be opened" % (self.out_path))
self.follow = follow self.follow = follow
self.compiledPlayers = set() self.compiledPlayers = set()

File diff suppressed because it is too large Load Diff

View File

@ -25,6 +25,7 @@ import datetime
import time import time
import re import re
import sys import sys
import locale
import Card import Card
@ -37,6 +38,8 @@ MYSQL_INNODB = 2
PGSQL = 3 PGSQL = 3
SQLITE = 4 SQLITE = 4
(localename, encoding) = locale.getdefaultlocale()
class DuplicateError(Exception): class DuplicateError(Exception):
def __init__(self, value): def __init__(self, value):
self.value = value self.value = value
@ -543,7 +546,7 @@ def parseActionType(line):
#parses the ante out of the given line and checks which player paid it, updates antes accordingly. #parses the ante out of the given line and checks which player paid it, updates antes accordingly.
def parseAnteLine(line, isTourney, names, antes): def parseAnteLine(line, isTourney, names, antes):
for i, name in enumerate(names): for i, name in enumerate(names):
if line.startswith(name.encode("latin-1")): if line.startswith(name.encode(encoding)):
pos = line.rfind("$") + 1 pos = line.rfind("$") + 1
if not isTourney: if not isTourney:
antes[i] += float2int(line[pos:]) antes[i] += float2int(line[pos:])
@ -705,7 +708,7 @@ def parseHandStartTime(topline):
def findName(line): def findName(line):
pos1 = line.find(":") + 2 pos1 = line.find(":") + 2
pos2 = line.rfind("(") - 1 pos2 = line.rfind("(") - 1
return unicode(line[pos1:pos2], "latin-1") return unicode(line[pos1:pos2], encoding)
def parseNames(lines): def parseNames(lines):
return [findName(line) for line in lines] return [findName(line) for line in lines]
@ -822,7 +825,7 @@ def parseTourneyNo(topline):
def parseWinLine(line, names, winnings, isTourney): def parseWinLine(line, names, winnings, isTourney):
#print "parseWinLine: line:",line #print "parseWinLine: line:",line
for i,n in enumerate(names): for i,n in enumerate(names):
n = n.encode("latin-1") n = n.encode(encoding)
if line.startswith(n): if line.startswith(n):
if isTourney: if isTourney:
pos1 = line.rfind("collected ") + 10 pos1 = line.rfind("collected ") + 10
@ -1033,13 +1036,13 @@ def recognisePlayerNo(line, names, atype):
#print "recogniseplayerno, names:",names #print "recogniseplayerno, names:",names
for i in xrange(len(names)): for i in xrange(len(names)):
if (atype=="unbet"): if (atype=="unbet"):
if (line.endswith(names[i].encode("latin-1"))): if (line.endswith(names[i].encode(encoding))):
return (i) return (i)
elif (line.startswith("Dealt to ")): elif (line.startswith("Dealt to ")):
#print "recognisePlayerNo, card precut, line:",line #print "recognisePlayerNo, card precut, line:",line
tmp=line[9:] tmp=line[9:]
#print "recognisePlayerNo, card postcut, tmp:",tmp #print "recognisePlayerNo, card postcut, tmp:",tmp
if (tmp.startswith(names[i].encode("latin-1"))): if (tmp.startswith(names[i].encode(encoding))):
return (i) return (i)
elif (line.startswith("Seat ")): elif (line.startswith("Seat ")):
if (line.startswith("Seat 10")): if (line.startswith("Seat 10")):
@ -1047,10 +1050,10 @@ def recognisePlayerNo(line, names, atype):
else: else:
tmp=line[8:] tmp=line[8:]
if (tmp.startswith(names[i].encode("latin-1"))): if (tmp.startswith(names[i].encode(encoding))):
return (i) return (i)
else: else:
if (line.startswith(names[i].encode("latin-1"))): if (line.startswith(names[i].encode(encoding))):
return (i) return (i)
#if we're here we mustve failed #if we're here we mustve failed
raise FpdbError ("failed to recognise player in: "+line+" atype:"+atype) raise FpdbError ("failed to recognise player in: "+line+" atype:"+atype)

View File

@ -1,271 +1,271 @@
# Code from http://ender.snowburst.org:4747/~jjohns/interlocks.py # Code from http://ender.snowburst.org:4747/~jjohns/interlocks.py
# Thanks JJ! # Thanks JJ!
import sys import sys
import os, os.path import os, os.path
import subprocess import subprocess
import time import time
import signal import signal
import base64 import base64
InterProcessLock = None InterProcessLock = None
""" """
Just use me like a thread lock. acquire() / release() / locked() Just use me like a thread lock. acquire() / release() / locked()
Differences compared to thread locks: Differences compared to thread locks:
1. By default, acquire()'s wait parameter is false. 1. By default, acquire()'s wait parameter is false.
2. When acquire fails, SingleInstanceError is thrown instead of simply returning false. 2. When acquire fails, SingleInstanceError is thrown instead of simply returning false.
3. acquire() can take a 3rd parameter retry_time, which, if wait is True, tells the locking 3. acquire() can take a 3rd parameter retry_time, which, if wait is True, tells the locking
mechanism how long to sleep between retrying the lock. Has no effect for unix/InterProcessLockFcntl. mechanism how long to sleep between retrying the lock. Has no effect for unix/InterProcessLockFcntl.
Differences in fpdb version to JJ's original: Differences in fpdb version to JJ's original:
1. Changed acquire() to return false like other locks 1. Changed acquire() to return false like other locks
2. Made acquire fail if same process already has the lock 2. Made acquire fail if same process already has the lock
""" """
class SingleInstanceError(RuntimeError): class SingleInstanceError(RuntimeError):
"Thrown when you try to acquire an InterProcessLock and another version of the process is already running." "Thrown when you try to acquire an InterProcessLock and another version of the process is already running."
class InterProcessLockBase: class InterProcessLockBase:
def __init__(self, name=None ): def __init__(self, name=None ):
self._has_lock = False self._has_lock = False
if not name: if not name:
name = sys.argv[0] name = sys.argv[0]
self.name = name self.name = name
def getHashedName(self): def getHashedName(self):
return base64.b64encode(self.name).replace('=','') return base64.b64encode(self.name).replace('=','')
def acquire_impl(self, wait): abstract def acquire_impl(self, wait): abstract
def acquire(self, wait=False, retry_time=1): def acquire(self, wait=False, retry_time=1):
if self._has_lock: # make sure 2nd acquire in same process fails if self._has_lock: # make sure 2nd acquire in same process fails
return False return False
while not self._has_lock: while not self._has_lock:
try: try:
self.acquire_impl(wait) self.acquire_impl(wait)
self._has_lock = True self._has_lock = True
#print 'i have the lock' #print 'i have the lock'
except SingleInstanceError: except SingleInstanceError:
if not wait: if not wait:
# raise # change back to normal acquire functionality, sorry JJ! # raise # change back to normal acquire functionality, sorry JJ!
return False return False
time.sleep(retry_time) time.sleep(retry_time)
return True return True
def release(self): def release(self):
self.release_impl() self.release_impl()
self._has_lock = False self._has_lock = False
def locked(self): def locked(self):
if self._has_lock: if self._has_lock:
return True return True
try: try:
self.acquire() self.acquire()
self.release() self.release()
return False return False
except SingleInstanceError: except SingleInstanceError:
return True return True
LOCK_FILE_DIRECTORY = '/tmp' LOCK_FILE_DIRECTORY = '/tmp'
class InterProcessLockFcntl(InterProcessLockBase): class InterProcessLockFcntl(InterProcessLockBase):
def __init__(self, name=None): def __init__(self, name=None):
InterProcessLockBase.__init__(self, name) InterProcessLockBase.__init__(self, name)
self.lockfd = 0 self.lockfd = 0
self.lock_file_name = os.path.join(LOCK_FILE_DIRECTORY, self.getHashedName() + '.lck') self.lock_file_name = os.path.join(LOCK_FILE_DIRECTORY, self.getHashedName() + '.lck')
assert(os.path.isdir(LOCK_FILE_DIRECTORY)) assert(os.path.isdir(LOCK_FILE_DIRECTORY))
# This is the suggested way to get a safe file name, but I like having a descriptively named lock file. # This is the suggested way to get a safe file name, but I like having a descriptively named lock file.
def getHashedName(self): def getHashedName(self):
import re import re
bad_filename_character_re = re.compile(r'/\?<>\\\:;\*\|\'\"\^=\.\[\]') bad_filename_character_re = re.compile(r'/\?<>\\\:;\*\|\'\"\^=\.\[\]')
return bad_filename_character_re.sub('_',self.name) return bad_filename_character_re.sub('_',self.name)
def acquire_impl(self, wait): def acquire_impl(self, wait):
self.lockfd = open(self.lock_file_name, 'w') self.lockfd = open(self.lock_file_name, 'w')
fcntrl_options = fcntl.LOCK_EX fcntrl_options = fcntl.LOCK_EX
if not wait: if not wait:
fcntrl_options |= fcntl.LOCK_NB fcntrl_options |= fcntl.LOCK_NB
try: try:
fcntl.flock(self.lockfd, fcntrl_options) fcntl.flock(self.lockfd, fcntrl_options)
except IOError: except IOError:
self.lockfd.close() self.lockfd.close()
self.lockfd = 0 self.lockfd = 0
raise SingleInstanceError('Could not acquire exclusive lock on '+self.lock_file_name) raise SingleInstanceError('Could not acquire exclusive lock on '+self.lock_file_name)
def release_impl(self): def release_impl(self):
fcntl.lockf(self.lockfd, fcntl.LOCK_UN) fcntl.lockf(self.lockfd, fcntl.LOCK_UN)
self.lockfd.close() self.lockfd.close()
self.lockfd = 0 self.lockfd = 0
try: try:
os.unlink(self.lock_file_name) os.unlink(self.lock_file_name)
except IOError: except IOError:
# We don't care about the existence of the file too much here. It's the flock() we care about, # We don't care about the existence of the file too much here. It's the flock() we care about,
# And that should just go away magically. # And that should just go away magically.
pass pass
class InterProcessLockWin32(InterProcessLockBase): class InterProcessLockWin32(InterProcessLockBase):
def __init__(self, name=None): def __init__(self, name=None):
InterProcessLockBase.__init__(self, name) InterProcessLockBase.__init__(self, name)
self.mutex = None self.mutex = None
def acquire_impl(self,wait): def acquire_impl(self,wait):
self.mutex = win32event.CreateMutex(None, 0, self.getHashedName()) self.mutex = win32event.CreateMutex(None, 0, self.getHashedName())
if win32api.GetLastError() == winerror.ERROR_ALREADY_EXISTS: if win32api.GetLastError() == winerror.ERROR_ALREADY_EXISTS:
self.mutex.Close() self.mutex.Close()
self.mutex = None self.mutex = None
raise SingleInstanceError('Could not acquire exclusive lock on ' + self.name) raise SingleInstanceError('Could not acquire exclusive lock on ' + self.name)
def release_impl(self): def release_impl(self):
self.mutex.Close() self.mutex.Close()
class InterProcessLockSocket(InterProcessLockBase): class InterProcessLockSocket(InterProcessLockBase):
def __init__(self, name=None): def __init__(self, name=None):
InterProcessLockBase.__init__(self, name) InterProcessLockBase.__init__(self, name)
self.socket = None self.socket = None
self.portno = 65530 - abs(self.getHashedName().__hash__()) % 32749 self.portno = 65530 - abs(self.getHashedName().__hash__()) % 32749
def acquire_impl(self, wait): def acquire_impl(self, wait):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try: try:
self.socket.bind(('127.0.0.1', self.portno)) self.socket.bind(('127.0.0.1', self.portno))
except socket.error: except socket.error:
self.socket.close() self.socket.close()
self.socket = None self.socket = None
raise SingleInstanceError('Could not acquire exclusive lock on ' + self.name) raise SingleInstanceError('Could not acquire exclusive lock on ' + self.name)
def release_impl(self): def release_impl(self):
self.socket.close() self.socket.close()
self.socket = None self.socket = None
# Set InterProcessLock to the correct type given the sysem parameters available # Set InterProcessLock to the correct type given the sysem parameters available
try: try:
import fcntl import fcntl
InterProcessLock = InterProcessLockFcntl InterProcessLock = InterProcessLockFcntl
except ImportError: except ImportError:
try: try:
import win32event import win32event
import win32api import win32api
import winerror import winerror
InterProcessLock = InterProcessLockWin32 InterProcessLock = InterProcessLockWin32
except ImportError: except ImportError:
import socket import socket
InterProcessLock = InterProcessLockSocket InterProcessLock = InterProcessLockSocket
def test_construct(): def test_construct():
""" """
# Making the name of the test unique so it can be executed my multiple users on the same machine. # Making the name of the test unique so it can be executed my multiple users on the same machine.
>>> test_name = 'InterProcessLockTest' +str(os.getpid()) + str(time.time()) >>> test_name = 'InterProcessLockTest' +str(os.getpid()) + str(time.time())
>>> lock1 = InterProcessLock(name=test_name) >>> lock1 = InterProcessLock(name=test_name)
>>> lock1.acquire() >>> lock1.acquire()
>>> lock2 = InterProcessLock(name=test_name) >>> lock2 = InterProcessLock(name=test_name)
>>> lock3 = InterProcessLock(name=test_name) >>> lock3 = InterProcessLock(name=test_name)
# Since lock1 is locked, other attempts to acquire it fail. # Since lock1 is locked, other attempts to acquire it fail.
>>> lock2.acquire() >>> lock2.acquire()
Traceback (most recent call last): Traceback (most recent call last):
... ...
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
>>> lock3.acquire() >>> lock3.acquire()
Traceback (most recent call last): Traceback (most recent call last):
... ...
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
# Release the lock and let lock2 have it. # Release the lock and let lock2 have it.
>>> lock1.release() >>> lock1.release()
>>> lock2.acquire() >>> lock2.acquire()
>>> lock3.acquire() >>> lock3.acquire()
Traceback (most recent call last): Traceback (most recent call last):
... ...
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
# Release it and give it back to lock1 # Release it and give it back to lock1
>>> lock2.release() >>> lock2.release()
>>> lock1.acquire() >>> lock1.acquire()
>>> lock2.acquire() >>> lock2.acquire()
Traceback (most recent call last): Traceback (most recent call last):
... ...
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
# Test lock status # Test lock status
>>> lock2.locked() >>> lock2.locked()
True True
>>> lock3.locked() >>> lock3.locked()
True True
>>> lock1.locked() >>> lock1.locked()
True True
>>> lock1.release() >>> lock1.release()
>>> lock2.locked() >>> lock2.locked()
False False
>>> lock3.locked() >>> lock3.locked()
False False
>>> lock1.locked() >>> lock1.locked()
False False
>>> if os.name == 'posix': >>> if os.name == 'posix':
... def os_independent_kill(pid): ... def os_independent_kill(pid):
... import signal ... import signal
... os.kill(pid, signal.SIGKILL) ... os.kill(pid, signal.SIGKILL)
... else: ... else:
... assert(os.name == 'nt') ... assert(os.name == 'nt')
... def os_independent_kill(pid): ... def os_independent_kill(pid):
... ''' http://www.python.org/doc/faq/windows/#how-do-i-emulate-os-kill-in-windows ''' ... ''' http://www.python.org/doc/faq/windows/#how-do-i-emulate-os-kill-in-windows '''
... import win32api ... import win32api
... import win32con ... import win32con
... import pywintypes ... import pywintypes
... handle = win32api.OpenProcess(win32con.PROCESS_TERMINATE , pywintypes.FALSE, pid) ... handle = win32api.OpenProcess(win32con.PROCESS_TERMINATE , pywintypes.FALSE, pid)
... return (0 != win32api.TerminateProcess(handle, 0)) ... return (0 != win32api.TerminateProcess(handle, 0))
# Test to acquire the lock in another process. # Test to acquire the lock in another process.
>>> def execute(cmd): >>> def execute(cmd):
... cmd = 'import time;' + cmd + 'time.sleep(10);' ... cmd = 'import time;' + cmd + 'time.sleep(10);'
... process = subprocess.Popen([sys.executable, '-c', cmd]) ... process = subprocess.Popen([sys.executable, '-c', cmd])
... pid = process.pid ... pid = process.pid
... time.sleep(2) # quick hack, but we test synchronization in the end ... time.sleep(2) # quick hack, but we test synchronization in the end
... return pid ... return pid
>>> pid = execute('import interlocks;a=interlocks.InterProcessLock(name=\\''+test_name+ '\\');a.acquire();') >>> pid = execute('import interlocks;a=interlocks.InterProcessLock(name=\\''+test_name+ '\\');a.acquire();')
>>> lock1.acquire() >>> lock1.acquire()
Traceback (most recent call last): Traceback (most recent call last):
... ...
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
>>> os_independent_kill(pid) >>> os_independent_kill(pid)
>>> time.sleep(1) >>> time.sleep(1)
>>> lock1.acquire() >>> lock1.acquire()
>>> lock1.release() >>> lock1.release()
# Testing wait # Testing wait
>>> pid = execute('import interlocks;a=interlocks.InterProcessLock(name=\\''+test_name+ '\\');a.acquire();') >>> pid = execute('import interlocks;a=interlocks.InterProcessLock(name=\\''+test_name+ '\\');a.acquire();')
>>> lock1.acquire() >>> lock1.acquire()
Traceback (most recent call last): Traceback (most recent call last):
... ...
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
>>> os_independent_kill(pid) >>> os_independent_kill(pid)
>>> lock1.acquire(True) >>> lock1.acquire(True)
>>> lock1.release() >>> lock1.release()
""" """
pass pass
if __name__=='__main__': if __name__=='__main__':
import doctest import doctest
doctest.testmod(optionflags=doctest.IGNORE_EXCEPTION_DETAIL) doctest.testmod(optionflags=doctest.IGNORE_EXCEPTION_DETAIL)

View File

@ -1,27 +1,27 @@
# script to update indexes on mysql (+other?) database # script to update indexes on mysql (+other?) database
select '1. Dropping indexes' as ' '; select '1. Dropping indexes' as ' ';
select 'Can''t drop messages indicate index already gone' as ' '; select 'Can''t drop messages indicate index already gone' as ' ';
ALTER TABLE `fpdb`.`Settings` DROP INDEX `id`; ALTER TABLE `fpdb`.`Settings` DROP INDEX `id`;
ALTER TABLE `fpdb`.`Sites` DROP INDEX `id`; ALTER TABLE `fpdb`.`Sites` DROP INDEX `id`;
ALTER TABLE `fpdb`.`Gametypes` DROP INDEX `id`; ALTER TABLE `fpdb`.`Gametypes` DROP INDEX `id`;
ALTER TABLE `fpdb`.`Players` DROP INDEX `id`; ALTER TABLE `fpdb`.`Players` DROP INDEX `id`;
ALTER TABLE `fpdb`.`Autorates` DROP INDEX `id`; ALTER TABLE `fpdb`.`Autorates` DROP INDEX `id`;
ALTER TABLE `fpdb`.`Hands` DROP INDEX `id`; ALTER TABLE `fpdb`.`Hands` DROP INDEX `id`;
ALTER TABLE `fpdb`.`BoardCards` DROP INDEX `id`; ALTER TABLE `fpdb`.`BoardCards` DROP INDEX `id`;
ALTER TABLE `fpdb`.`TourneyTypes` DROP INDEX `id`; ALTER TABLE `fpdb`.`TourneyTypes` DROP INDEX `id`;
ALTER TABLE `fpdb`.`Tourneys` DROP INDEX `id`; ALTER TABLE `fpdb`.`Tourneys` DROP INDEX `id`;
ALTER TABLE `fpdb`.`TourneysPlayers` DROP INDEX `id`; ALTER TABLE `fpdb`.`TourneysPlayers` DROP INDEX `id`;
ALTER TABLE `fpdb`.`HandsPlayers` DROP INDEX `id`; ALTER TABLE `fpdb`.`HandsPlayers` DROP INDEX `id`;
ALTER TABLE `fpdb`.`HandsActions` DROP INDEX `id`; ALTER TABLE `fpdb`.`HandsActions` DROP INDEX `id`;
ALTER TABLE `fpdb`.`HudCache` DROP INDEX `id`; ALTER TABLE `fpdb`.`HudCache` DROP INDEX `id`;
select '2. Adding extra indexes on useful fields' as ' '; select '2. Adding extra indexes on useful fields' as ' ';
select 'Duplicate key name messages indicate new indexes already there' as ' '; select 'Duplicate key name messages indicate new indexes already there' as ' ';
ALTER TABLE `fpdb`.`tourneys` ADD INDEX `siteTourneyNo`(`siteTourneyNo`); ALTER TABLE `fpdb`.`tourneys` ADD INDEX `siteTourneyNo`(`siteTourneyNo`);
ALTER TABLE `fpdb`.`hands` ADD INDEX `siteHandNo`(`siteHandNo`); ALTER TABLE `fpdb`.`hands` ADD INDEX `siteHandNo`(`siteHandNo`);
ALTER TABLE `fpdb`.`players` ADD INDEX `name`(`name`); ALTER TABLE `fpdb`.`players` ADD INDEX `name`(`name`);