File indexing completed on 2024-04-21 04:01:56

0001 # -*- coding: utf-8 -*-
0002 
0003 """
0004 Copyright (C) 2009-2016 Wolfgang Rohdewald <wolfgang@rohdewald.de>
0005 
0006 SPDX-License-Identifier: GPL-2.0
0007 
0008 
0009 The DBPasswordChecker is based on an example from the book
0010 Twisted Network Programming Essentials by Abe Fettig, 2006
0011 O'Reilly Media, Inc., ISBN 0-596-10032-9
0012 """
0013 
0014 import datetime
0015 
0016 from twisted.internet.defer import fail
0017 from twisted.spread import pb
0018 
0019 from common import Internal, Debug, Options, StrMixin
0020 from servercommon import srvError
0021 from log import logDebug
0022 from mi18n import i18nE
0023 from query import Query
0024 
0025 class User(pb.Avatar, StrMixin):
0026 
0027     """the twisted avatar"""
0028 
0029     def __init__(self, userid):
0030         self.name = Query(
0031             'select name from player where id=?',
0032             (userid,
0033             )).records[0][0]
0034         self.mind = None
0035         self.server = None
0036         self.dbIdent = None
0037         self.voiceId = None
0038         self.maxGameId = None
0039         self.lastPing = None
0040         self.pinged()
0041 
0042     def pinged(self):
0043         """time of last ping or message from user"""
0044         self.lastPing = datetime.datetime.now()
0045         if self.server:
0046             self.server.lastPing = self.lastPing
0047 
0048     def source(self):
0049         """how did he connect?"""
0050         result = str(self.mind.broker.transport.getPeer())
0051         if 'UNIXAddress' in result:
0052             # socket: we want to get the socket name
0053             result = Options.socket
0054         return result
0055 
0056     def attached(self, mind):
0057         """override pb.Avatar.attached"""
0058         self.mind = mind
0059         self.server.login(self)
0060 
0061     def detached(self, unusedMind):
0062         """override pb.Avatar.detached"""
0063         if Debug.connections:
0064             logDebug(
0065                 '%s: connection detached from %s' %
0066                 (self, self.source()))
0067         self.server.logout(self)
0068         self.mind = None
0069 
0070     def perspective_setClientProperties(
0071             self, dbIdent, voiceId, maxGameId, clientVersion=None):
0072         """perspective_* methods are to be called remotely"""
0073         self.pinged()
0074         self.dbIdent = dbIdent
0075         self.voiceId = voiceId
0076         self.maxGameId = maxGameId
0077         serverVersion = str(Internal.defaultPort)
0078         if clientVersion != serverVersion:
0079             # we assume that versions x.y.* are compatible
0080             if clientVersion is None:
0081                 # client passed no version info
0082                 return fail(srvError(pb.Error,
0083                                      i18nE(
0084                                          'Your client has a version older than 4.9.0 but you need %1 for this server'),
0085                                      serverVersion))
0086             commonDigits = len([x for x in zip(
0087                 clientVersion.split('.'),
0088                 serverVersion.split('.'))
0089                                 if x[0] == x[1]])
0090             if commonDigits < 2:
0091                 return fail(srvError(pb.Error,
0092                                      i18nE(
0093                                          'Your client has version %1 but you need %2 for this server'),
0094                                      clientVersion or '<4.9.0',
0095                                      '.'.join(serverVersion.split('.')[:2]) + '.*'))
0096         if Debug.table:
0097             logDebug('client has dbIdent={} voiceId={} maxGameId={} clientVersion {}'.format(
0098                 self.dbIdent, self.voiceId, self.maxGameId, clientVersion))
0099         self.server.sendTables(self)
0100         return None
0101 
0102     def perspective_ping(self):
0103         """perspective_* methods are to be called remotely"""
0104         return self.pinged()
0105 
0106     def perspective_needRulesets(self, rulesetHashes):
0107         """perspective_* methods are to be called remotely"""
0108         return self.server.needRulesets(rulesetHashes)
0109 
0110     def perspective_joinTable(self, tableid):
0111         """perspective_* methods are to be called remotely"""
0112         return self.server.joinTable(self, tableid)
0113 
0114     def perspective_leaveTable(self, tableid):
0115         """perspective_* methods are to be called remotely"""
0116         return self.server.leaveTable(self, tableid, None)
0117 
0118     def perspective_newTable(
0119             self, ruleset, playOpen, autoPlay, wantedGame: str, tableId=None):
0120         """perspective_* methods are to be called remotely"""
0121         return self.server.newTable(self, ruleset, playOpen, autoPlay, wantedGame, tableId)
0122 
0123     def perspective_startGame(self, tableid):
0124         """perspective_* methods are to be called remotely"""
0125         return self.server.startGame(self, tableid)
0126 
0127     def perspective_logout(self):
0128         """perspective_* methods are to be called remotely"""
0129         self.detached(None)
0130 
0131     def perspective_chat(self, chatString):
0132         """perspective_* methods are to be called remotely"""
0133         self.pinged()
0134         return self.server.chat(chatString)
0135 
0136     def __str__(self):
0137         return self.name