diff options
Diffstat (limited to 'modules/modpy/py.cpp')
| -rw-r--r-- | modules/modpy/py.cpp | 265 | 
1 files changed, 265 insertions, 0 deletions
diff --git a/modules/modpy/py.cpp b/modules/modpy/py.cpp new file mode 100644 index 0000000..51cb38f --- /dev/null +++ b/modules/modpy/py.cpp @@ -0,0 +1,265 @@ +/* + *	bitz-server, An ICAP server implementation in C++ + *	Copyright (C) 2012	Uditha Atukorala + * + *	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, write to the Free Software + *	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include "py.h" +#include "interface.h" + +#include <bitz/config.h> +#include <bitz/logger.h> + + +namespace bitz { + +	Py::Py() : Modifier() { + +		// defaults +		_pymodule = NULL; + +		// initialise Py::config_t values +		_config.module_name = "modpy"; +		_config.module_path = ""; + +		// load configs +		load_configs(); + +		// initialise python +		init_python(); + +	} + + +	Py::~Py() { + +		// cleanup python +		cleanup_python(); + +	} + + +	icap::Response * Py::modify( icap::Request * request ) throw() { + +		// get the modify response +		return python_response( request, "modify" ); + +	} + + +	icap::Response * Py::preview( icap::Request * request ) throw() { + +		// get the preview response +		return python_response( request, "preview" ); + +	} + + +	void Py::load_configs() throw() { + +		std::string s; +		Config &server_config = Config::instance(); + +		// interface module name +		s = server_config.module_config( "modpy", "module_name" ); +		if ( s != "" ) { +			_config.module_name = s; +		} + +		// module lookup path +		_config.module_path = server_config.module_config( "modpy", "module_path" ); + +	} + + +	void Py::init_python() throw() { + +		PyObject * sys_path; +		PyObject * pymodule_path, * pymodule_name; +		PyObject * pymethod; +		PyObject * pyreturn; + +		// logger +		Logger &logger = Logger::instance(); + +		// python core +		Py_Initialize(); + +		// bitz python module +		if ( Py_InitModule( "bitz", bitz_methods ) == NULL ) { +			logger.warn( "[modpy] failed to init C interface module: bitz" ); +		} + +		// setup python environment +		if ( _config.module_path != "" ) { + +			logger.debug( std::string( "[modpy] appending to sys.path, module_path: " ).append( _config.module_path ) ); + +			sys_path      = PySys_GetObject( (char *) "path" ); +			pymodule_path = PyString_FromString( _config.module_path.c_str() ); +			PyList_Append( sys_path, pymodule_path ); + +		} + +		// load the interface module +		logger.debug( std::string( "[modpy] interface module: " ).append( _config.module_name ) ); + +		pymodule_name = PyString_FromString( _config.module_name.c_str() ); +		_pymodule     = PyImport_Import( pymodule_name ); + +		if ( _pymodule != NULL ) { + +			logger.debug( "[modpy] interface module loaded successfully" ); + +			// call init() in the interface module +			pymethod = PyObject_GetAttrString( _pymodule, "init" ); + +			if ( pymethod && PyCallable_Check( pymethod ) ) { +				pyreturn = PyObject_CallObject( pymethod, NULL ); +				Py_DECREF( pyreturn ); +			} else { +				logger.warn ( "[modpy] failed to call init() in interface module" ); +			} + +			Py_DECREF( pymethod ); + +		} else { +			logger.warn( "[modpy] failed to load interface module" ); +		} + + +		// cleanup +		Py_DECREF( pymodule_name ); +		Py_DECREF( pymodule_path ); +		Py_DECREF( sys_path ); + +	} + + +	void Py::cleanup_python() throw() { + +		PyObject * pymethod; +		PyObject * pyreturn; + +		// logger +		Logger &logger = Logger::instance(); + + +		// cleanup +		if ( _pymodule != NULL ) { + +			// call cleanup() in the interface module +			pymethod = PyObject_GetAttrString( _pymodule, "cleanup" ); + +			if ( pymethod && PyCallable_Check( pymethod ) ) { +				pyreturn = PyObject_CallObject( pymethod, NULL ); +				Py_DECREF( pyreturn ); +			} else { +				logger.warn ( "[modpy] failed to call cleanup() in interface module" ); +			} + +			Py_DECREF( pymethod ); +			Py_DECREF( _pymodule ); + +		} + +		// finalise python core +		Py_Finalize(); + +	} + + +	icap::Response * Py::python_response( icap::Request * request, const std::string &method ) throw() { + +		/* +		*  notes: +		*    + pass icap::Request to python module as a PyCapsule object +		*      so it can be used to grab the data needed using the C/C++ interface. +		*    + process data (within the python module) and use the C/C++ interface +		*      to create a icap::Response and pass it back to this method +		*      using a PyCapsule object +		*/ + +		icap::Response * response; + +		PyObject * pymethod; +		PyObject * pyargs; +		PyObject * pyrequest, * pyresponse; + +		// logger +		Logger &logger = Logger::instance(); + +		// initialise the response object +		response = NULL; + +		// check for the interface module +		if ( _pymodule != NULL ) { + +			/* call the [method]() in the interface module */ +			pymethod  = PyObject_GetAttrString( _pymodule, method.c_str() ); +			pyargs    = PyTuple_New( 1 ); +			pyrequest = PyCapsule_New( (void *) request, "request", NULL ); +			PyTuple_SetItem( pyargs, 0, pyrequest ); + +			if ( pymethod && PyCallable_Check( pymethod ) ) { + +				// get the response capsule +				pyresponse = PyObject_CallObject( pymethod, pyargs ); + +				// sanity check +				if ( pyresponse != NULL ) { + +					void * p = PyCapsule_GetPointer( pyresponse, "response" ); + +					// sanity check +					if ( p != NULL ) { + +						// construct the response +						response = static_cast<icap::Response *>(p); + +					} else { +						logger.warn( std::string( "[modpy] invalid capsule response, method: " ).append( method ) ); +					} + +					Py_DECREF( pyresponse ); + +				} else { +					logger.warn( std::string( "[modpy] response is NULL, method: " ).append( method ) ); +				} + + +			} else { +				logger.warn ( std::string( "[modpy] failed to call the method in interface module, method: " ).append( method ) ); +			} + +			// cleanup +			// pyrequest is created from the reference passed in +			Py_DECREF( pyargs ); +			Py_DECREF( pymethod ); + +		} + +		// sanity check +		if ( response == NULL ) { +			response = new icap::Response( icap::ResponseHeader::SERVER_ERROR ); +		} + +		return response; + +	} + +} /* end of namespace bitz */ +  | 
