diff options
Diffstat (limited to 'python/modules/IcePy/Connection.cpp')
-rw-r--r-- | python/modules/IcePy/Connection.cpp | 155 |
1 files changed, 115 insertions, 40 deletions
diff --git a/python/modules/IcePy/Connection.cpp b/python/modules/IcePy/Connection.cpp index c761419993a..2aa28f893df 100644 --- a/python/modules/IcePy/Connection.cpp +++ b/python/modules/IcePy/Connection.cpp @@ -37,18 +37,18 @@ struct ConnectionObject Ice::CommunicatorPtr* communicator; }; -class ConnectionCallbackI : public Ice::ConnectionCallback +class CloseCallbackI : public Ice::CloseCallback { public: - ConnectionCallbackI(PyObject* cb, PyObject* con) : + CloseCallbackI(PyObject* cb, PyObject* con) : _cb(cb), _con(con) { Py_INCREF(cb); Py_INCREF(con); } - virtual ~ConnectionCallbackI() + virtual ~CloseCallbackI() { AdoptThread adoptThread; // Ensure the current thread is able to call into Python. @@ -56,52 +56,94 @@ public: Py_DECREF(_con); } - virtual void heartbeat(const Ice::ConnectionPtr& con) - { - invoke("heartbeat", con); - } - virtual void closed(const Ice::ConnectionPtr& con) { - invoke("closed", con); + invoke(con); } private: - void invoke(const string& methodName, const Ice::ConnectionPtr& con) + void invoke(const Ice::ConnectionPtr& con) { AdoptThread adoptThread; // Ensure the current thread is able to call into Python. #ifndef NDEBUG ConnectionObject* c = reinterpret_cast<ConnectionObject*>(_con); assert(con == *(c->connection)); #endif - if(!PyObject_HasAttrString(_cb, STRCAST(methodName.c_str()))) + + PyObjectHandle args = Py_BuildValue(STRCAST("(O)"), _con); + assert(_cb); + PyObjectHandle tmp = PyObject_Call(_cb, args.get(), 0); + if(PyErr_Occurred()) { - ostringstream ostr; - ostr << "connection callback object does not define " << methodName << "()"; - string str = ostr.str(); - PyErr_Warn(PyExc_RuntimeWarning, const_cast<char*>(str.c_str())); + PyException ex; // Retrieve it before another Python API call clears it. + + // + // A callback that calls sys.exit() will raise the SystemExit exception. + // This is normally caught by the interpreter, causing it to exit. + // However, we have no way to pass this exception to the interpreter, + // so we act on it directly. + // + ex.checkSystemExit(); + + ex.raise(); } - else + } + + PyObject* _cb; + PyObject* _con; +}; + +class HeartbeatCallbackI : public Ice::HeartbeatCallback +{ +public: + + HeartbeatCallbackI(PyObject* cb, PyObject* con) : + _cb(cb), _con(con) + { + Py_INCREF(cb); + Py_INCREF(con); + } + + virtual ~HeartbeatCallbackI() + { + AdoptThread adoptThread; // Ensure the current thread is able to call into Python. + + Py_DECREF(_cb); + Py_DECREF(_con); + } + + virtual void heartbeat(const Ice::ConnectionPtr& con) + { + invoke(con); + } + +private: + + void invoke(const Ice::ConnectionPtr& con) + { + AdoptThread adoptThread; // Ensure the current thread is able to call into Python. +#ifndef NDEBUG + ConnectionObject* c = reinterpret_cast<ConnectionObject*>(_con); + assert(con == *(c->connection)); +#endif + + PyObjectHandle args = Py_BuildValue(STRCAST("(O)"), _con); + assert(_cb); + PyObjectHandle tmp = PyObject_Call(_cb, args.get(), 0); + if(PyErr_Occurred()) { - PyObjectHandle args = Py_BuildValue(STRCAST("(O)"), _con); - PyObjectHandle method = PyObject_GetAttrString(_cb, STRCAST(methodName.c_str())); - assert(method.get()); - PyObjectHandle tmp = PyObject_Call(method.get(), args.get(), 0); - if(PyErr_Occurred()) - { - PyException ex; // Retrieve it before another Python API call clears it. - - // - // A callback that calls sys.exit() will raise the SystemExit exception. - // This is normally caught by the interpreter, causing it to exit. - // However, we have no way to pass this exception to the interpreter, - // so we act on it directly. - // - ex.checkSystemExit(); - - ex.raise(); - } + PyException ex; // Retrieve it before another Python API call clears it. + + // + // A callback that calls sys.exit() will raise the SystemExit exception. + // This is normally caught by the interpreter, causing it to exit. + // However, we have no way to pass this exception to the interpreter, + // so we act on it directly. + // + ex.checkSystemExit(); + + ex.raise(); } } @@ -437,22 +479,53 @@ connectionEndFlushBatchRequests(ConnectionObject* self, PyObject* args) extern "C" #endif static PyObject* -connectionSetCallback(ConnectionObject* self, PyObject* args) +connectionSetCloseCallback(ConnectionObject* self, PyObject* args) +{ + assert(self->connection); + + PyObject* callbackType = lookupType("types.FunctionType"); + PyObject* cb; + if(!PyArg_ParseTuple(args, STRCAST("O!"), callbackType, &cb)) + { + return 0; + } + + Ice::CloseCallbackPtr wrapper = new CloseCallbackI(cb, reinterpret_cast<PyObject*>(self)); + try + { + AllowThreads allowThreads; // Release Python's global interpreter lock during blocking invocations. + (*self->connection)->setCloseCallback(wrapper); + } + catch(const Ice::Exception& ex) + { + setPythonException(ex); + return 0; + } + + Py_INCREF(Py_None); + return Py_None; +} + +#ifdef WIN32 +extern "C" +#endif +static PyObject* +connectionSetHeartbeatCallback(ConnectionObject* self, PyObject* args) { assert(self->connection); - PyObject* callbackType = lookupType("Ice.ConnectionCallback"); + PyObject* callbackType = lookupType("types.FunctionType"); PyObject* cb; if(!PyArg_ParseTuple(args, STRCAST("O!"), callbackType, &cb)) { return 0; } - Ice::ConnectionCallbackPtr wrapper = new ConnectionCallbackI(cb, reinterpret_cast<PyObject*>(self)); + Ice::HeartbeatCallbackPtr wrapper = new HeartbeatCallbackI(cb, reinterpret_cast<PyObject*>(self)); try { AllowThreads allowThreads; // Release Python's global interpreter lock during blocking invocations. - (*self->connection)->setCallback(wrapper); + (*self->connection)->setHeartbeatCallback(wrapper); } catch(const Ice::Exception& ex) { @@ -754,8 +827,10 @@ static PyMethodDef ConnectionMethods[] = METH_VARARGS | METH_KEYWORDS, PyDoc_STR(STRCAST("begin_flushBatchRequests([_ex][, _sent]) -> Ice.AsyncResult")) }, { STRCAST("end_flushBatchRequests"), reinterpret_cast<PyCFunction>(connectionEndFlushBatchRequests), METH_VARARGS, PyDoc_STR(STRCAST("end_flushBatchRequests(Ice.AsyncResult) -> None")) }, - { STRCAST("setCallback"), reinterpret_cast<PyCFunction>(connectionSetCallback), METH_VARARGS, - PyDoc_STR(STRCAST("setCallback(Ice.ConnectionCallback) -> None")) }, + { STRCAST("setCloseCallback"), reinterpret_cast<PyCFunction>(connectionSetCloseCallback), METH_VARARGS, + PyDoc_STR(STRCAST("setCloseCallback(Ice.CloseCallback) -> None")) }, + { STRCAST("setHeartbeatCallback"), reinterpret_cast<PyCFunction>(connectionSetHeartbeatCallback), METH_VARARGS, + PyDoc_STR(STRCAST("setHeartbeatCallback(Ice.HeartbeatCallback) -> None")) }, { STRCAST("setACM"), reinterpret_cast<PyCFunction>(connectionSetACM), METH_VARARGS, PyDoc_STR(STRCAST("setACM(int, Ice.ACMClose, Ice.ACMHeartbeat) -> None")) }, { STRCAST("getACM"), reinterpret_cast<PyCFunction>(connectionGetACM), METH_NOARGS, |