#!/usr/bin/python -O
#
# baseClient.py
#	Description:	A basic client for baseserver.  Unless you need to do
#			something special, you should not need to write your
#			own client for your server.  This client automagically
#			knows what commands the server offers and lets the user
#			call them.  It is currently limited to four args for
#			the server functions, so if you need more, either
#			make a class that inherits this one and make a member
#			function there (easy), or hack Client to allow more
#			args.  BTW - this was not my choice... python's scoping
#			sucks with lambdas.
#
#	Requires: 	xmlrpc
#
#
#	Copyright:	LGPL
#	Created:	March 20, 2001
#	Author:		Chris Jensen - chris@sourcelight.com
#
#	Last Update:	04/25/2001
#
#####################################################################################

import xmlrpc

LOG_LEVEL	= 0
ClientError	= 'ClientError'
ERR_CLOSE	= 'Connection is closed.  Call reconnect.'
NONE		= []

# Client
#
# Client(host, port, timeout)
#	Constructor.  host and port are the server to connect to.  timeout is the
#	maximum time you should wait for the server to procedd your request.  A
#	value less than 0 means block until the server responds.
#
# reconnect()
#	Reconnect to the server if the connection is lost.
#
# The rest of the callable functions are provided by the server.  To get a command
# list, call the usage function, which SHOULD return a complete list of functions
# and thier usage.  Obviously, if you write the server, you know what's there.
#
class Client:
	def __init__(self, host, port, timeout=-1.0):
		self.host	= host			# host
		self.port	= port			# server port
		self.timeout	= timeout		# xmlrpc timeout
		self.client	= xmlrpc.client(host, port)
		xmlrpc.setLogLevel(LOG_LEVEL)
		self.cmds	= self.__talk__('getclient')
		if not self.cmds:
			raise ClientError, 'could not get command list'

	def __getattr__(self, fn):
		if fn not in self.cmds:
			raise AttributeError, '%s instance has no attribute %s' % (
						self.__class__, fn)
		return (lambda a1=NONE,a2=NONE,a3=NONE,a4=NONE,x=fn,y=self.__talk__:
				y(x, a1, a2, a3, a4))

###
## special commands.
##
	# kill the server
	#
	def kill(self):
		if not self.client:
			raise ClientError, ERR_CLOSE
		self.timeout	= 1.0
		try:	self.__talk__('kill')
		except:	pass
		self.client	= None

	# disconnect from the server
	#
	def leave(self):
		self.__talk__('leave')
		self.client	= None

	# reconnect to the server
	#
	def reconnect(self):
		self.client	= xmlrpc.client(self.host, self.port)

###
## helper functions
##
	# do a send and receive with the server
	#
	def __talk__(self, command, *args):
		args	= filter(lambda x,y=NONE: (x is not y), args)
		if not self.client:
			raise ClientError, ERR_CLOSE
		try:
			return self.client.execute(command, args,
						   timeout=self.timeout)
		except:
			self.client	= xmlrpc.client(self.host, self.port)
			return self.client.execute(command, args,
						   timeout=self.timeout)


syntax highlighted by Code2HTML, v. 0.9.1