NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

connectionService.py (13791B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\carbon\client\script\remote\connectionService.py
      2 import sys
      3 import blue
      4 import localization
      5 import log
      6 import telemetry
      7 import uthread
      8 import uthread2
      9 from carbon.common.lib import const, serverInfo
     10 from carbon.common.script.net.GPSExceptions import GPSException
     11 from carbon.common.script.sys import basesession, serviceConst
     12 from carbon.common.script.sys.service import Service
     13 from carbon.common.script.util.exceptionEater import ExceptionEater
     14 from carbon.common.script.util.format import FmtTime
     15 from carbonui import uiconst
     16 from carbonui.uicore import uicore
     17 from eve.common.lib.jwt import is_jwt
     18 from eveexceptions import UserError
     19 from eveprefs import prefs
     20 from globalConfig.getFunctions import GetMaxConnectionIdleTime
     21 from player_messaging.client.ui_message import prompt_player_fsd_dialog
     22 from utillib import GetServerName, GetServerPort, GetLoginCredentials
     23 DEFAULTLONGWAITWARNINGSECS = 300
     24 LONGWAITWARNINGMETHODS = ['MachoBindObject', 'SelectCharacterID']
     25 LoginProgressLabels = {'loginprogress::authenticating': '/Carbon/UI/Login/Progress/Authenticating',
     26  'loginprogress::connecting': '/Carbon/UI/Login/Progress/Connecting',
     27  'loginprogress::done': '/Carbon/UI/Login/Progress/Done',
     28  'loginprogress::lowlevelversioncheck': '/Carbon/UI/Login/Progress/LowLevelVersionCheck'}
     29 MIN_SYNC_TIME_IN_MINUTES = 1
     30 MAX_SYNC_TIME_IN_MINUTES = 3
     31 
     32 class ConnectionService(Service):
     33     __guid__ = 'svc.connection'
     34     __servicename__ = 'connection'
     35     __displayname__ = 'Network Connection Service'
     36     __exportedcalls__ = {'Connect': [],
     37      'Disconnect': [],
     38      'IsConnected': [],
     39      'ConnectToService': [],
     40      'Login': []}
     41     __dependencies__ = ['machoNet']
     42     __notifyevents__ = ['OnProcessLoginProgress']
     43 
     44     def __init__(self):
     45         Service.__init__(self)
     46         self.shell = None
     47         self.reentrancyGaurd = 0
     48         self.clocksynchronizing = 0
     49         self.clocklastsynchronized = None
     50         self.lastLongCallTimestamp = 0
     51         self.loginJWT = None
     52         self.accessToken = None
     53         self.computerHash = None
     54         blue.pyos.synchro.timesyncs.append(self.OnTimerResync)
     55 
     56     def Run(self, *args):
     57         Service.Run(self, *args)
     58         uthread.worker('ConnectionService::LongCallTimer', self.__LongCallTimer)
     59 
     60     def OnTimerResync(self, old, new):
     61         if session and session.nextSessionChange:
     62             diff = new - old
     63             log.general.Log('Readjusting next session change by %.3f seconds' % (diff / float(const.SEC)), log.LGINFO)
     64             session.nextSessionChange += diff
     65 
     66     @telemetry.ZONE_METHOD
     67     def Connect(self, host, port, userid, password, ct):
     68         try:
     69             self.LogInfo('calling connect')
     70             address = '%s:%d' % (str(host), port)
     71             response = self.machoNet.ConnectToServer(address, userid, password, ct)
     72             self.LogInfo('connect completed...')
     73         except GPSException as what:
     74             self.LogError('connect failed %s' % what)
     75             raise UserError('LoginConnectFailed', {'what': what})
     76 
     77         self.SynchronizeClock()
     78         uthread.new(self.ClockSyncDaemon)
     79         uthread2.start_tasklet(self.PingLoop)
     80         return response
     81 
     82     def ConnectSso(self, host, port, token, ct):
     83         try:
     84             self.LogInfo('calling connect')
     85             address = '%s:%d' % (str(host), port)
     86             response = self.machoNet.ConnectToServer(address, 'EVE-SSO-CONNECTION', 'fakePW', ct, token)
     87             self.LogInfo('connect completed...')
     88         except GPSException as what:
     89             self.LogError('connect failed %s' % what)
     90             raise UserError('LoginConnectFailed', {'what': what})
     91 
     92         self.SynchronizeClock()
     93         uthread.new(self.ClockSyncDaemon)
     94         uthread2.start_tasklet(self.PingLoop)
     95         return response
     96 
     97     @telemetry.ZONE_METHOD
     98     def OnProcessLoginProgress(self, what, prefix = None, current = 1, total = 1, response = None):
     99         if what not in LoginProgressLabels.keys():
    100             text = "Unexpected step in OnProcessLoginProgress, '%s'" % what
    101             log.LogTraceback(extraText=text, severity=log.LGERR)
    102             return
    103         useMorph = 1
    104         msg = localization.GetByLabel(LoginProgressLabels[what])
    105         uthread.new(sm.GetService('loading').ProgressWnd, localization.GetByLabel('/Carbon/UI/Login/LoggingIn'), msg, current, total, useMorph=useMorph, autoTick=useMorph)
    106         blue.pyos.synchro.Yield()
    107 
    108     @telemetry.ZONE_METHOD
    109     def Login(self, loginparam):
    110         if self.reentrancyGaurd:
    111             return
    112         self.reentrancyGaurd = 1
    113         try:
    114             if loginparam is None:
    115                 raise RuntimeError('loginparam can not be None anymore dude')
    116             if loginparam[4]:
    117                 ct = 'udp'
    118             else:
    119                 ct = 'tcp'
    120             response = self.Connect(loginparam[2], loginparam[3], loginparam[0], loginparam[1], ct)
    121             return response
    122         finally:
    123             self.reentrancyGaurd = 0
    124 
    125     def LoginSso(self, token):
    126         if self.reentrancyGaurd:
    127             return
    128         self.reentrancyGaurd = 1
    129         try:
    130             if token is None:
    131                 raise RuntimeError('Trying to do an SSO log in without an SSO token')
    132             if is_jwt(token):
    133                 self.loginJWT = token
    134             response = self.ConnectSso(serverInfo.GetServerIP(GetServerName()), GetServerPort(), token, 'tcp')
    135             self.accessToken = response['access_token']
    136             self.computerHash = response['computer_hash']
    137             return response
    138         finally:
    139             self.reentrancyGaurd = 0
    140 
    141     def GetLoginJWT(self):
    142         return self.loginJWT
    143 
    144     def GetAccessToken(self):
    145         return self.accessToken
    146 
    147     def GetComputerHash(self):
    148         return self.computerHash
    149 
    150     def Disconnect(self, silently = 0):
    151         if self.reentrancyGaurd:
    152             return
    153         self.reentrancyGaurd = 1
    154         try:
    155             self.machoNet.DisconnectFromServer()
    156         finally:
    157             self.reentrancyGaurd = 0
    158 
    159     def ConnectToProxyService(self, serviceName):
    160         return session.ConnectToRemoteService(serviceName, sm.services['machoNet'].myProxyNodeID)
    161 
    162     def ConnectToService(self, serviceName):
    163         return session.ConnectToRemoteService(serviceName)
    164 
    165     def IsConnected(self):
    166         return self.machoNet.IsConnected()
    167 
    168     def PingLoop(self):
    169         while self.IsConnected():
    170             maxIdleTime = GetMaxConnectionIdleTime(self.machoNet)
    171             if maxIdleTime <= 0:
    172                 log.LogInfo('Ping inactive')
    173                 uthread2.sleep(300)
    174                 continue
    175             sleepTime = maxIdleTime
    176             with ExceptionEater('Exception during ping loop'):
    177                 transport = self.machoNet.GetTransport('ip:packet:server').transport
    178                 idleTime = transport.GetIdleTime()
    179                 if idleTime >= maxIdleTime:
    180                     log.LogInfo('Ping after %d seconds idle time' % idleTime)
    181                     sm.ProxySvc('pingService').Ping()
    182                     idleTime = 0
    183                 sleepTime = maxIdleTime - idleTime
    184                 log.LogInfo('Ping loop sleeping for %d seconds' % sleepTime)
    185             uthread2.sleep(sleepTime)
    186 
    187     def ClockSyncDaemon(self):
    188         syncRateMS = MAX_SYNC_TIME_IN_MINUTES * 60 * 1000
    189         while self.IsConnected():
    190             with ExceptionEater('Exception during soft clock sync'):
    191                 blue.synchro.SleepWallclock(syncRateMS)
    192                 log.LogInfo('*** Soft Clock Sync Starting ***')
    193                 results = []
    194                 numPings = 5
    195                 blue.os.timeSyncAdjust = 0
    196                 for i in xrange(numPings):
    197                     myTime = blue.os.GetWallclockTimeNow()
    198                     serverTime = sm.ProxySvc('machoNet').GetTime()
    199                     now = blue.os.GetWallclockTimeNow()
    200                     elaps = now - myTime
    201                     serverTime += elaps / 2
    202                     diff = float(now - serverTime)
    203                     results.append((elaps, diff))
    204                     log.LogInfo('SoftClock:', elaps, diff)
    205 
    206                 averageElaps = sum([ x[0] for x in results ]) / numPings
    207                 results = filter(lambda x: x[0] < averageElaps * 1.2, results)
    208                 log.LogInfo('SoftClock results:', results)
    209                 avgDiff = sum([ x[1] for x in results ]) / len(results)
    210                 log.LogInfo('*** Soft Clock Sync adjusting by', -avgDiff / const.SEC, 'seconds')
    211                 blue.os.timeSyncAdjust = long(-avgDiff)
    212                 if abs(avgDiff) > 3 * const.SEC:
    213                     log.LogError('Having to adjust more than 3 seconds in a single timesync interval! (%fs per %ds)' % (avgDiff / float(const.SEC), syncRateMS / 1000))
    214                     syncRateMS = max(MIN_SYNC_TIME_IN_MINUTES * 60 * 1000, syncRateMS - 60000)
    215                 else:
    216                     syncRateMS = min(MAX_SYNC_TIME_IN_MINUTES * 60 * 1000, syncRateMS + 60000)
    217                 driftFactor = abs(avgDiff) / float(syncRateMS * const.MSEC)
    218                 driftFactor = min(0.95, max(0.02, driftFactor))
    219                 blue.os.timeSyncAdjustFactor = driftFactor
    220 
    221     def SynchronizeClock(self, firstTime = 1, maxIterations = 5):
    222         log.general.Log('connection.synchronizeClock called', log.LGINFO)
    223         if not firstTime:
    224             if self.clocklastsynchronized is not None and blue.os.GetWallclockTime() - self.clocklastsynchronized < const.HOUR:
    225                 return
    226         if self.clocksynchronizing:
    227             return
    228         self.clocklastsynchronized = blue.os.GetWallclockTime()
    229         self.clocksynchronizing = 1
    230         try:
    231             diff = 0
    232             goodCount = 0
    233             lastElaps = None
    234             log.general.Log('***   ***   ***   ***   Clock Synchronizing loop initiating      ***   ***   ***   ***', log.LGINFO)
    235             for i in range(maxIterations):
    236                 myTime = blue.os.GetWallclockTimeNow()
    237                 serverTime = sm.ProxySvc('machoNet').GetTime()
    238                 now = blue.os.GetWallclockTimeNow()
    239                 elaps = now - myTime
    240                 serverTime += elaps / 2
    241                 diff = float(now - serverTime) / float(const.SEC)
    242                 if diff > 2.0 and not firstTime:
    243                     logflag = log.LGERR
    244                 else:
    245                     logflag = log.LGINFO
    246                 log.general.Log('Synchronizing clock diff %.3f sec elaps %f sec.' % (diff, elaps / float(const.SEC)), logflag)
    247                 if lastElaps is None or elaps < lastElaps and elaps < const.SEC:
    248                     goodCount += 1
    249                     log.general.Log('Synchronizing clock:  iteration completed, setting time', logflag)
    250                     blue.pyos.synchro.ResetClock(serverTime)
    251                     lastElaps = elaps
    252                 else:
    253                     log.general.Log('Synchronizing clock:  iteration ignored as it was less accurate (%f) than our current time (%f)' % (elaps / float(const.SEC), lastElaps / float(const.SEC)), log.LGINFO)
    254                 if goodCount >= 3:
    255                     break
    256                 firstTime = 0
    257 
    258             log.general.Log('***   ***   ***   ***   Clock Synchronizing loop completed       ***   ***   ***   ***', log.LGINFO)
    259         finally:
    260             self.clocksynchronizing = 0
    261 
    262     def IsClockSynchronizing(self):
    263         if self.clocksynchronizing:
    264             log.general.Log('Clock synchronization in progress', log.LGINFO)
    265         return self.clocksynchronizing
    266 
    267     def __LongCallTimer(self):
    268         longWarningSecs = prefs.GetValue('longOutstandingCallWarningSeconds', DEFAULTLONGWAITWARNINGSECS)
    269         sleepSecs = 60
    270         if longWarningSecs < sleepSecs:
    271             sleepSecs = longWarningSecs
    272         self.LogInfo('__LongCallTimer reporting warnings after', longWarningSecs, 'seconds and checking every', sleepSecs, 'seconds')
    273 
    274         def ShouldWarn(method):
    275             for w in LONGWAITWARNINGMETHODS:
    276                 if w in repr(method):
    277                     return True
    278 
    279             return False
    280 
    281         while self.state == serviceConst.SERVICE_RUNNING:
    282             if sm.GetService('machoNet').GetGlobalConfig().get('disableLongCallWarning'):
    283                 self.LogWarn('__LongCallTimer should not be running! Exiting.')
    284                 return
    285             blue.pyos.synchro.SleepWallclock(sleepSecs * 1000)
    286             try:
    287                 maxDiff = 0
    288                 for ct in basesession.outstandingCallTimers:
    289                     method = ct[0]
    290                     t = ct[1]
    291                     diff = blue.os.GetWallclockTimeNow() - t
    292                     if diff > maxDiff and ShouldWarn(method):
    293                         maxDiff = diff
    294                     if diff > 60 * const.SEC:
    295                         self.LogWarn('Have waited', FmtTime(diff), 'for', method)
    296 
    297                 if maxDiff > longWarningSecs * const.SEC and self.lastLongCallTimestamp < blue.os.GetWallclockTimeNow() - longWarningSecs * const.SEC:
    298                     modalWnd = uicore.registry.GetModalWindow()
    299                     if modalWnd:
    300                         modalWnd.SetModalResult(uiconst.ID_CLOSE)
    301                     uthread.new(prompt_player_fsd_dialog, 'LongWaitForRemoteCall', {'time': int(maxDiff / const.MIN)})
    302                     self.lastLongCallTimestamp = blue.os.GetWallclockTimeNow()
    303             except:
    304                 log.LogException()
    305                 sys.exc_clear()
    306 
    307     def TryAutomaticLogin(self):
    308         if GetLoginCredentials() is None or session.userid is not None:
    309             return
    310         username, password = GetLoginCredentials()
    311         self.Login((username,
    312          password,
    313          GetServerName(),
    314          GetServerPort(),
    315          None))