Bases: foundry.rpc.communicator.RPCCommunicator, foundry.rpc.dispatcher.RPCDispatcher
An RPCClient manages a single connection to an RPCServer, when the two can be connected on the same host and port, via sockets.
There can be many clients connecting to a single server, but only a single server.
Once a client object is started (using the connectToServer method), it spawns a thread that continually tries to connect to the server running on the same host/port. Once the client is connected, the thread blocks and waits for any messages sent from the server to the client. The client’s thread will also send a ‘heartbeat’ message every once in awhile. If it doesn’t get a valid response from the server, it assumes that something bad has occurred and it closes the connection.
Clients have the following options:
To receive notification when certain events occur, the RPCClient class can be derived from and the following methods can be declared in the base class to deal with these events:
The server registers proxy objects with the client by name. To send a command to the server, you can call remoteProxyObject() and specify the name of the object to retrieve. You can then call methods on the object as if it was an object running in a currently loaded module.
For example:
# get a server command object; assumes that "serverCommands"
# has been registered by the server with the client
serverCommands = server.remoteProxyObject("serverCommands")
# call the printMessage method on the serverCommands object. Will send the message
# over to the server which will dispatch it to the serverCommands object running
# in the server environment.
serverCommands.printMessage("Hello World!")
Returns True if the client can start.
@return: True or False
Returns True if the client can stop
@return: True or False
Tells the client to connect to the server. The client will spawn a separate thread, and will block on a socket read until it connects to the server. Once it connects to the server, it will block waiting for commands from the server or a disconnect. In the event of a disconnect, it will attempt to reconnect, until/unless disconnectFromServer() is called.
Returns the connectionID, which is the value that the server uses to identify this client with. This value is sent over to the client by the server when it first connects. A timeout may occur, and the client may disconnect and reconnect to the server; in that case, the connectionID may change over the life time of the client object.
@return: string
Signals the client to stop connecting to the server. Has no effect if the client was already disconnecting.
Returns True if the client is currently connected.
@return: True or False
Sends a unique identifier for this client to the server. The server keeps track of this identifier and users of the server can then read the unique identifier per client.
@param identifier: string
Gets the status of the client.
@return: status string; one of (RPCClient.STATUS_AUTO_CONNECTING, RPCClient.STATUS_DISCONNECTED, RPCClient.STATUS_CONNECTING, RPCClient.STATUS_CONNECTED, RPCClient.STATUS_DISCONNECTING)
Called when the status of the client changes. This method can be overridden by derived classes to be notified when the client status changes. The default implementation does nothing. Be aware that this method may be called on threads other than the main thread.
For example:
class CustomClient(RPCClient):
def statusChanged(self, newStatus):
print "Client status changed to: %s" % newStatus
if newStatus == RPCClient.STATUS_DISCONNECTED:
print "Client is not running"
@param newStatus: one of (RPCClient.STATUS_AUTO_CONNECTING, RPCClient.STATUS_DISCONNECTED, RPCClient.STATUS_CONNECTING, RPCClient.STATUS_CONNECTED, RPCClient.STATUS_DISCONNECTING)
Bases: foundry.rpc.dispatcher.RPCDispatcher
An RPCServer manages connections between itself and clients, connected on the same host address and port, via sockets.
There can be only one server, but many clients. If a server is started but detects that another is already running, a ServerAlreadyRunningException will be raised.
Once started, the server spawns a thread which blocks until the socket on the host address and port is connected to by a client.
Once a connection is made, communication carries on between the two on the same host address, but with a different port (as selected by the OS) and over a different socket. For each new connection made, the server spawns another thread to listen for communication coming from the connected client. This thread will also send a ‘heartbeat’ message every once in awhile. If it doesn’t get a valid response from the client, it assumes that something bad has occurred and it closes the connection.
Servers have the following options:
Once connected, a client can be referred to by a connectonID, which will be unique to that client. Currently connected client connectionIDs can be retrieved with the connections() method.
To receive notification when certain events occur, the RPCServer class can be derived from and the following methods can be declared in the base class to deal with these events:
Clients register proxy objects with the server by name. To send a command to a client, you can call remoteProxyObject() and specify the connectionID (for the client you want to communicate with) and the name of the object to retrieve. You can then call methods on the object as if it was an object running in a currently loaded module.
For example:
# get a client connection to communicate with
clientConnectionID = server.connections()[0]
# get a client command object; assumes that "clientCommands"
# has been registered by the client with the server
clientCommands = server.remoteProxyObject(clientConnectionID, "clientCommands")
# call the printMessage method on the clientCommands object. Will send the message
# over to the client which will dispatch it to the clientCommands object running
# in the client environment.
clientCommands.printMessage("Hello World!")
Called when a client connects to the server. This method can be overridden by derived classes, to deal with a new client connection. The default implementation does nothing. Be aware that this method will not be called on the main thread.
For example:
class CustomServer(RPCServer):
def connectionMade(self, connectionID):
# since this is not called on the main thread, we don't want to update the ui directly here
def addMenuItem():
self.connectionListMenu.addNewMenuItem(self.connectionID)
runOnMainThread(addMenuItem)
@param connectionID: the connectionID of the newly connected client
Gets a status string for the connection specified. @param connectionID: the id of the client to get the status for @return: status string; one of (RPCClient.STATUS_AUTO_CONNECTING, RPCClient.STATUS_DISCONNECTED, RPCClient.STATUS_CONNECTING, RPCClient.STATUS_CONNECTED, RPCClient.STATUS_DISCONNECTING)
Gets a possibly helpful unique string of text for the client connection specified. @param connectionID: id of the client to get the unique identifier for @return: string
Gets the client connection ids. @return: list of connection
Called when a client disconnects to (or is disconnected from) the server. Also called when the communication with the client times out. This method can be overridden by derived classes, to deal with a new client connection. The default implementation does nothing. Be aware that this method will not be called on the main thread.
For example:
class CustomServer(RPCServer):
def disconnectionMade(self, connectionID):
# since this is not called on the main thread, we don't want to update the ui directly here
def removeMenuItem():
self.connectionListMenu.removeMenuItem(self.connectionID)
runOnMainThread(removeMenuItem)
@param connectionID: the connectionID of the disconnected client
Returns True if the server is currently starting up or already running
@return: True or False
Called to access a remote proxy object that has been previously registered by a client. @param connectionID: the id of the client to get the object from; an exception will occur if the connectionID is invalid @param name: the name of the object to retrieve @return: a proxy object that can be used to send commands to the matching object on the client, or None if an object with the name requested was not registered.
Called when a client registers a remote object that can be called. This method can be overridden by derived classes, which can then perform certain actions when particular proxy objects are registered. The default implementation does nothing. Be aware that this method will not be called on the main thread.
For example:
class CustomServer(RPCServer):
def remoteProxyObjectRegistered(self, connectionID, name):
if name == "Bank":
bank = self.remoteProxyObject(connectionID, "Bank")
bank.giveMeAllYourMoney()
@param connectionID: the connectionID of the client that the new proxy object is running in @param name: the name of the newly registered object
Sets the maximum number of client connections that the server will connect to at one time.
@param maxConnectionsAllowed: the maximum number of connections to allow, or None to remove any maximum
Sets the timeout to allow before the server suspects an error has occurred when communicating with a client
@param timeoutInSeconds: the timeout to allow, in seconds
Tells the server to start listening for client connections and communicating with any that do connect. It will first test to see if another server is already running, and if it is, will raise a ServerAlreadyRunningException exception. Otherwise, a thread is spawned to listen for client connections and to communicate with them.
Gets the status of the server. @return: status string; one of (RPCServer.STATE_NOT_RUNNING, RPCServer.STATE_STARTING, RPCServer.STATE_RUNNING, RPCServer.STATE_STOPPING)
Called when the status of the server changes. This method can be overridden by derived classes to be notified when the server status changes. The default implementation does nothing. Be aware that this method may be called on threads other than the main thread.
For example:
class CustomServer(RPCServer):
def statusChanged(self, newStatus):
print "Server status changed to: %s" % newStatus
if newStatus == RPCServer.STATE_NOT_RUNNING:
print "Server is not running"
@param newStatus: one of (RPCServer.STATE_NOT_RUNNING, RPCServer.STATE_STARTING, RPCServer.STATE_RUNNING, RPCServer.STATE_STOPPING)
Tells the server to stop listening for client connections and to disconnect from any currently connected.
Bases: exceptions.BaseException
Exception thrown when a Server at the specified port and address is already running
runOnMainThreadWithResult(callable, *args, **kwargs) -> ensures that the callable is executed on the main thread, blocking until it does and returning the result.
Use this method to interact with the user interface from threads other than the main (user interface) thread. Qt/PySide requires that all widget manipulation happens on the thread that created the widgets, and runOnMainThreadWithResult allows you to execute functions and methods on the main thread and get the result back.
If runOnMainThreadWithResult is called from the main (user interface) thread, the callable will be executed immediately without blocking the currently running thread.
@return: result of callable
runOnMainThread(callable, *args, **kwargs) -> ensures that the callable is executed on the main thread. Does not block until completion.
Use this method to interact with the user interface from threads other than the main (user interface) thread. Qt/PySide requires that all widget manipulation happens on the thread that created the widgets, and runOnMainThreadWithResult allows you to execute functions and methods on the main thread.
If runOnMainThread is called from the main (user interface) thread, the callable will be executed immediately.
If runOnMainThread is called from another thread, the callable (and the args and kwargs) is queued up and will be executed the next time the main (user interface) thread’s event queue is processed.
Callables sent to runOnMainThread from non-main threads will be executed in the order that runOnMainThread is called. Callables sent to runOnMainThread from the main thread are executed immediately, regardless of whether or not other callables sent earlier to runOnMainThread has been executed already or not.
@return: result of callable