Source code for lib_openmolar.common.connect.proxy_client
#! /usr/bin/env python
# -*- coding: utf-8 -*-
###############################################################################
## ##
## Copyright 2010, Neil Wallace <rowinggolfer@googlemail.com> ##
## ##
## This program is free software: you can redistribute it and/or modify ##
## it under the terms of the GNU General Public License as published by ##
## the Free Software Foundation, either version 3 of the License, or ##
## (at your option) any later version. ##
## ##
## This program is distributed in the hope that it will be useful, ##
## but WITHOUT ANY WARRANTY; without even the implied warranty of ##
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ##
## GNU General Public License for more details. ##
## ##
## You should have received a copy of the GNU General Public License ##
## along with this program. If not, see <http://www.gnu.org/licenses/>. ##
## ##
###############################################################################
import socket
import pickle
import xmlrpclib
from lib_openmolar.common.datatypes import Connection230Data
from lib_openmolar.common.connect import ProxyUser
class _ConnectionError(Exception):
'''
a custom Exception - becomes a property of :doc:`ProxyClient`
'''
pass
class _PermissionError(Exception):
'''
A custom exception raised when user privileges are insufficient
becomes a property of :doc:`ProxyClient`
'''
pass
[docs]class ProxyClient(object):
'''
This class provides functionality for communicating with the 230 server.
(the openmolar xmlrpc server)
'''
_server = None
_is_connecting = False
#:
PermissionError = _PermissionError
#:
ConnectionError = _ConnectionError
[docs] def __init__(self, connection230_data, user=None):
'''
:param:host(string)
:param:port(int)
:param:user :doc:`ProxyUser` or None
'''
assert type(connection230_data) == Connection230Data, \
"ProxyClient must be initiated with a Connection230Data object"
self.connection230_data = connection230_data
if user is None:
user = ProxyUser()
self.set_user(user)
#socket.setdefaulttimeout(5.0)
def __repr__(self):
return "%s (connected = %s) (connecting = %s)"% (
self.name, self.is_connected, self.is_connecting)
[docs] def set_user(self, user):
assert type(user) == ProxyUser, \
"user must be of type ProxyUser"
self.user = user
self._server = None
[docs] def connect(self):
'''
attempt to connect to xmlrpc_server, and return this object
raise a ConnectionError if no success.
'''
if self.user.has_expired:
LOGGER.warning("ProxyUser has expired - using default ProxyUser")
self.user = ProxyUser()
location = 'https://%s:%s@%s:%d'% (self.user.name, self.user.psword,
self.connection230_data.host, self.connection230_data.port)
LOGGER.debug("attempting connection to %s"%
location.replace(self.user.psword, "********"))
self._is_connecting = True
try:
_server = xmlrpclib.ServerProxy(location)
LOGGER.debug("server proxy created.. will attempt ping")
_server.ping()
LOGGER.debug("connected and pingable (this is very good!)")
self._server = _server
except xmlrpclib.ProtocolError:
self._is_connecting = False
message = u"%s '%s'"% (_("connection refused for user"),
self.user.name)
LOGGER.error(message)
raise self.ConnectionError(message)
except socket.error as e:
self._is_connecting = False
raise self.ConnectionError(
'Is the host %s running and accepting connections on port %d?'% (
self.connection230_data.host, self.connection230_data.port))
self._is_connecting = False
@property
[docs] def server(self):
'''
a bridge to remote functions on the XMLRPC server
'''
if self.is_connecting:
LOGGER.debug("awaiting connection")
if self._server is None:
try:
self.connect()
except self.ConnectionError:
LOGGER.exception
self._server = None
return self._server
@property
[docs] def is_connected(self):
'''
A boolean value stating whether the client is connected
(to a proxy server)
'''
return self._server is not None
@property
[docs] def is_connecting(self):
'''
A boolean stating whether the connection is in progress
(happens in a thread)
'''
return self._is_connecting
@property
[docs] def brief_name(self):
return self.connection230_data.name
@property
[docs] def name(self):
return "ProxyClient for %s"% (self.connection230_data)
@property
[docs] def host(self):
return self.connection230_data.host
@property
[docs] def html(self):
'''
poll the openmolar xml_rpc server for messages
'''
if self._server is not None:
try:
payload = pickle.loads(self.server.admin_welcome())
if not payload.permission:
raise self.PermissionError
message = payload.payload
except xmlrpclib.Fault:
LOGGER.exception("error getting proxy message")
message = '''<h1>Unexpected server error!</h1>
please check the log and report a bug.'''
except Exception:
return "unknown error in proxy_message"
else:
message = '''<h1>No connection</h1>%s<br />
<a href='Retry_230_connection'>%s</a>'''% (
self.connection230_data, _("Try Again"))
return message
def _test():
import logging
logging.basicConfig(level = logging.DEBUG)
import __builtin__
__builtin__.__dict__["LOGGER"] = logging.getLogger()
import gettext
gettext.install("openmolar")
conn_data = Connection230Data()
conn_data.default_connection()
pc = ProxyClient(conn_data)
#admin_user = ProxyUser("admin", "dSqhZ0pt")
#pc.set_user(admin_user)
if pc.server is not None:
print pc.server.system.listMethods()
LOGGER.debug("getting last backup")
payload = pickle.loads(pc.server.last_backup())
LOGGER.debug("received payload %s"% payload)
if payload.payload:
LOGGER.debug("last backup %s"% payload.payload)
else:
LOGGER.error(payload.error_message)
LOGGER.debug('ProxyClient.name = "%s"'% pc.name)
#LOGGER.debug(pc.html)
if __name__ == "__main__":
_test()