support connectHttp

This commit is contained in:
David Rose 2002-10-21 14:50:53 +00:00
parent 5f859b3901
commit ebc6b3f7d0

View File

@ -8,7 +8,6 @@ import Task
import DirectNotifyGlobal import DirectNotifyGlobal
import ClientDistClass import ClientDistClass
import CRCache import CRCache
import Datagram
# The repository must import all known types of Distributed Objects # The repository must import all known types of Distributed Objects
#import DistributedObject #import DistributedObject
#import DistributedToon #import DistributedToon
@ -26,6 +25,23 @@ class ClientRepository(DirectObject.DirectObject):
self.doId2cdc={} self.doId2cdc={}
self.parseDcFile(dcFileName) self.parseDcFile(dcFileName)
self.cache=CRCache.CRCache() self.cache=CRCache.CRCache()
# Set this true to establish a connection to the server using
# the HTTPClient interface, which ultimately uses the OpenSSL
# socket library (even though SSL is not involved). This is
# not as robust a socket library as NSPR's, but the HTTPClient
# interface does a good job of negotiating the connection over
# an HTTP proxy if one is in use.
# Set it false to use Panda's net interface
# (e.g. QueuedConnectionManager, etc.) to establish the
# connection, which ultimately uses the NSPR socket library.
# This is a much better socket library, but it may be more
# than you need for most applications; and the Panda net
# interface doesn't support proxies at all.
self.connectHttp = base.config.GetBool('connect-http', 1)
self.tcpConn = None
return None return None
def parseDcFile(self, dcFileName): def parseDcFile(self, dcFileName):
@ -47,66 +63,64 @@ class ClientRepository(DirectObject.DirectObject):
self.name2cdc[dcClass.getName()]=clientDistClass self.name2cdc[dcClass.getName()]=clientDistClass
return None return None
def connect(self, serverName, serverPort): def connect(self, serverURL,
self.qcm=QueuedConnectionManager() successCallback = None, successArgs = [],
failureCallback = None, failureArgs = []):
"""
Attempts to establish a connection to the server. May return
before the connection is established. The two callbacks
represent the two functions to call (and their arguments) on
success or failure, respectively. The failure callback also
gets one additional parameter, which will be passed in first:
the return status code giving reason for failure, if it is
known.
"""
if self.connectHttp:
ch = self.http.makeChannel(0)
ch.beginConnectTo(serverURL)
ch.spawnTask(name = 'connect-to-server',
callback = self.httpConnectCallback,
extraArgs = [ch, successCallback, successArgs,
failureCallback, failureArgs])
else:
self.qcm = QueuedConnectionManager()
gameServerTimeoutMs = base.config.GetInt("game-server-timeout-ms", gameServerTimeoutMs = base.config.GetInt("game-server-timeout-ms",
20000) 20000)
# A big old 20 second timeout. # A big old 20 second timeout.
self.tcpConn = self.qcm.openTCPClientConnection( self.tcpConn = self.qcm.openTCPClientConnection(
serverName, serverPort, gameServerTimeoutMs) serverURL.getServer(), serverURL.getPort(),
# Test for bad connection gameServerTimeoutMs)
if self.tcpConn == None:
return None if self.tcpConn:
else:
self.tcpConn.setNoDelay(1) self.tcpConn.setNoDelay(1)
self.qcr=QueuedConnectionReader(self.qcm, 0) self.qcr=QueuedConnectionReader(self.qcm, 0)
self.qcr.addConnection(self.tcpConn) self.qcr.addConnection(self.tcpConn)
self.cw=ConnectionWriter(self.qcm, 0) self.cw=ConnectionWriter(self.qcm, 0)
self.startReaderPollTask() self.startReaderPollTask()
return self.tcpConn if successCallback:
successCallback(*successArgs)
def startRawReaderPollTask(self):
# Stop any tasks we are running now
self.stopRawReaderPollTask()
self.stopReaderPollTask()
task = Task.Task(self.rawReaderPollUntilEmpty)
# Start with empty string
task.currentRawString = ""
taskMgr.add(task, "rawReaderPollTask", priority=self.TASK_PRIORITY)
return None
def stopRawReaderPollTask(self):
taskMgr.remove("rawReaderPollTask")
return None
def rawReaderPollUntilEmpty(self, task):
while self.rawReaderPollOnce():
pass
return Task.cont
def rawReaderPollOnce(self):
self.notify.debug("rawReaderPollOnce")
self.ensureValidConnection()
availGetVal = self.qcr.dataAvailable()
if availGetVal:
datagram = NetDatagram()
readRetVal = self.qcr.getData(datagram)
if readRetVal:
str = datagram.getMessage()
self.notify.debug("rawReaderPollOnce: found str: " + str)
self.handleRawString(str)
else: else:
ClientRepository.notify.warning("getData returned false") # Failed to connect.
return availGetVal if failureCallback:
failureCallback(0, *failureArgs)
def handleRawString(self, str): def httpConnectCallback(self, ch, successCallback, successArgs,
# This method is meant to be pure virtual, and any classes that failureCallback, failureArgs):
# inherit from it need to make their own handleRawString method if ch.isConnectionReady():
pass self.tcpConn = ch.getConnection()
self.tcpConn.userManagesMemory = 1
self.startReaderPollTask()
if successCallback:
successCallback(*successArgs)
else:
# Failed to connect.
if failureCallback:
failureCallback(ch.getStatusCode(), *failureArgs)
def startReaderPollTask(self): def startReaderPollTask(self):
# Stop any tasks we are running now # Stop any tasks we are running now
self.stopRawReaderPollTask()
self.stopReaderPollTask() self.stopReaderPollTask()
taskMgr.add(self.readerPollUntilEmpty, "readerPollTask", taskMgr.add(self.readerPollUntilEmpty, "readerPollTask",
priority=self.TASK_PRIORITY) priority=self.TASK_PRIORITY)
@ -122,25 +136,42 @@ class ClientRepository(DirectObject.DirectObject):
return Task.cont return Task.cont
def readerPollOnce(self): def readerPollOnce(self):
self.ensureValidConnection() if self.connectHttp:
availGetVal = self.qcr.dataAvailable() datagram = Datagram()
if availGetVal: if self.tcpConn.receiveDatagram(datagram):
# print "Client: Incoming message!"
datagram = NetDatagram()
readRetVal = self.qcr.getData(datagram)
if readRetVal:
self.handleDatagram(datagram) self.handleDatagram(datagram)
return 1
# Unable to receive a datagram: did we lose the connection?
if self.tcpConn.isClosed():
self.tcpConn = None
self.loginFSM.request("noConnection")
return 0
else: else:
ClientRepository.notify.warning("getData returned false") self.ensureValidConnection()
return availGetVal if self.qcr.dataAvailable():
datagram = NetDatagram()
if self.qcr.getData(datagram):
self.handleDatagram(datagram)
return 1
return 0
def ensureValidConnection(self): def ensureValidConnection(self):
# Was the connection reset? # Was the connection reset?
if self.connectHttp:
pass
else:
if self.qcm.resetConnectionAvailable(): if self.qcm.resetConnectionAvailable():
resetConnectionPointer = PointerToConnection() resetConnectionPointer = PointerToConnection()
if self.qcm.getResetConnection(resetConnectionPointer): if self.qcm.getResetConnection(resetConnectionPointer):
self.qcm.closeConnection(resetConnectionPointer.p()) resetConn = resetConnectionPointer.p()
self.qcm.closeConnection(resetConn)
if self.tcpConn.this == resetConn.this:
self.tcpConn = None
self.loginFSM.request("noConnection") self.loginFSM.request("noConnection")
else:
self.notify.warning("Lost unknown connection.")
return None return None
def handleDatagram(self, datagram): def handleDatagram(self, datagram):
@ -386,7 +417,7 @@ class ClientRepository(DirectObject.DirectObject):
return None return None
def sendSetShardMsg(self, shardId): def sendSetShardMsg(self, shardId):
datagram = Datagram.Datagram() datagram = Datagram()
# Add message type # Add message type
datagram.addUint16(CLIENT_SET_SHARD) datagram.addUint16(CLIENT_SET_SHARD)
# Add shard id # Add shard id
@ -396,7 +427,7 @@ class ClientRepository(DirectObject.DirectObject):
return None return None
def sendSetZoneMsg(self, zoneId): def sendSetZoneMsg(self, zoneId):
datagram = Datagram.Datagram() datagram = Datagram()
# Add message type # Add message type
datagram.addUint16(CLIENT_SET_ZONE) datagram.addUint16(CLIENT_SET_ZONE)
# Add zone id # Add zone id
@ -420,6 +451,14 @@ class ClientRepository(DirectObject.DirectObject):
print "ClientRepository sending datagram:" print "ClientRepository sending datagram:"
datagram.dumpHex(ostream) datagram.dumpHex(ostream)
if not self.tcpConn:
self.notify.warning("Unable to send message after connection is closed.")
return
if self.connectHttp:
if not self.tcpConn.sendDatagram(datagram):
self.notify.warning("Could not send datagram.")
else:
self.cw.send(datagram, self.tcpConn) self.cw.send(datagram, self.tcpConn)
return None return None