
14 changed files with 313 additions and 347 deletions
@ -0,0 +1,96 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#include "user_interface.hh" |
|||
#include <assert.h> |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
Adapter::Adapter() |
|||
{ |
|||
session(init); |
|||
} |
|||
|
|||
Adapter::~Adapter() |
|||
{ |
|||
session(release); |
|||
} |
|||
|
|||
PEP_SESSION Adapter::session(session_action action) |
|||
{ |
|||
lock_guard<mutex> lock(mtx); |
|||
|
|||
thread_local static PEP_SESSION _session = nullptr; |
|||
thread_local int booked = 0; |
|||
PEP_STATUS status = PEP_STATUS_OK; |
|||
|
|||
switch (action) { |
|||
case release: |
|||
if (booked) |
|||
--booked; |
|||
if (!booked && _session) { |
|||
::release(_session); |
|||
_session = nullptr; |
|||
} |
|||
break; |
|||
|
|||
case none: |
|||
if (_session) |
|||
break; |
|||
|
|||
case init: |
|||
++booked; |
|||
if (!_session) |
|||
status = ::init(&_session, _messageToSend, _inject_sync_event); |
|||
break; |
|||
|
|||
default: |
|||
status = PEP_ILLEGAL_VALUE; |
|||
} |
|||
|
|||
if (status) |
|||
_throw_status(status); |
|||
|
|||
return _session; |
|||
} |
|||
|
|||
PyObject *Adapter::ui_object(PyObject *value) |
|||
{ |
|||
lock_guard<mutex> lock(mtx); |
|||
static PyObject *obj = nullptr; |
|||
if (value) |
|||
obj = value; |
|||
return obj; |
|||
} |
|||
|
|||
PEP_STATUS Adapter::_messageToSend(struct _message *msg) |
|||
{ |
|||
if (!msg) |
|||
return PEP_ILLEGAL_VALUE; |
|||
|
|||
adapter.messageToSend(Message(msg)); |
|||
return PEP_STATUS_OK; |
|||
} |
|||
|
|||
int Adapter::_inject_sync_event(SYNC_EVENT ev, void *management) |
|||
{ |
|||
if (is_sync_thread(adapter.session())) { |
|||
PEP_STATUS status = do_sync_protocol_step(adapter.session(), adapter.ui_object(), ev); |
|||
return status == PEP_STATUS_OK ? 0 : 1; |
|||
} |
|||
|
|||
try { |
|||
q.push_front(ev); |
|||
} |
|||
catch (exception&) { |
|||
return 1; |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
void Adapter_callback::messageToSend(Message msg) { |
|||
call_method< void >(_self, "messageToSend", msg); |
|||
} |
|||
} |
|||
} |
|||
|
@ -0,0 +1,62 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#pragma once |
|||
|
|||
#include "pEpmodule.hh" |
|||
#include "locked_queue.hh" |
|||
#include "user_interface.hh" |
|||
#include <pEp/sync_api.h> |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
using Message = pEp::PythonAdapter::Message; |
|||
|
|||
class Adapter { |
|||
public: |
|||
Adapter(); |
|||
virtual ~Adapter(); |
|||
|
|||
virtual void messageToSend(Message msg) { |
|||
throw runtime_error("override this method"); |
|||
} |
|||
|
|||
enum session_action { |
|||
none = 0, |
|||
init, |
|||
release |
|||
}; |
|||
|
|||
PEP_SESSION session(session_action action = none); |
|||
static ::utility::locked_queue< SYNC_EVENT > q; |
|||
|
|||
protected: |
|||
static PyObject *ui_object(PyObject *value = nullptr); |
|||
static PEP_STATUS _messageToSend(struct _message *msg); |
|||
static int _inject_sync_event(SYNC_EVENT ev, void *management); |
|||
|
|||
private: |
|||
static mutex mtx; |
|||
|
|||
// non copyable
|
|||
Adapter(const Adapter&) = delete; |
|||
Adapter& operator= (const Adapter&) = delete; |
|||
|
|||
friend class UserInterface_callback; |
|||
}; |
|||
|
|||
class Adapter_callback : public Adapter { |
|||
PyObject *_self; |
|||
public: |
|||
Adapter_callback(PyObject *self) : _self(self) { } |
|||
~Adapter_callback() { } |
|||
|
|||
void messageToSend(Message msg); |
|||
|
|||
// non copyable
|
|||
Adapter_callback(const Adapter_callback&) = delete; |
|||
Adapter_callback& operator= (const Adapter_callback&) = delete; |
|||
}; |
|||
} |
|||
} |
|||
|
@ -1,186 +0,0 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#include "sync_mixin.hh" |
|||
#ifndef NDEBUG |
|||
#include <pEp/KeySync_fsm.h> |
|||
#endif |
|||
#include <assert.h> |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
SyncMixIn_callback::SyncMixIn_callback(PyObject *self) : _self(self) |
|||
{ |
|||
PEP_STATUS status = register_sync_callbacks(session, (void *) this, |
|||
_messageToSend, _notifyHandshake, inject_sync_msg, |
|||
retrieve_next_sync_msg); |
|||
assert(status == PEP_STATUS_OK); |
|||
} |
|||
|
|||
SyncMixIn_callback::~SyncMixIn_callback() |
|||
{ |
|||
unregister_sync_callbacks(session); |
|||
} |
|||
|
|||
PEP_STATUS SyncMixIn::_messageToSend(void *obj, message *msg) |
|||
{ |
|||
if (!obj) |
|||
return PEP_SEND_FUNCTION_NOT_REGISTERED; |
|||
|
|||
if (!msg) |
|||
return PEP_ILLEGAL_VALUE; |
|||
|
|||
auto that = dynamic_cast< SyncMixIn_callback * >( |
|||
static_cast< SyncMixIn * > (obj)); |
|||
that->messageToSend(Message(msg)); |
|||
|
|||
return PEP_STATUS_OK; |
|||
} |
|||
|
|||
PEP_STATUS SyncMixIn::_notifyHandshake(void *obj, |
|||
pEp_identity *me, pEp_identity *partner, sync_handshake_signal signal) |
|||
{ |
|||
if (!obj) |
|||
return PEP_SEND_FUNCTION_NOT_REGISTERED; |
|||
|
|||
if (!(me && partner)) |
|||
return PEP_ILLEGAL_VALUE; |
|||
|
|||
auto that = dynamic_cast< SyncMixIn_callback * >( |
|||
static_cast< SyncMixIn * > (obj)); |
|||
that->notifyHandshake(Identity(me), Identity(partner), signal); |
|||
|
|||
return PEP_STATUS_OK; |
|||
} |
|||
|
|||
void SyncMixIn::deliverHandshakeResult(Identity partner, int result) |
|||
{ |
|||
PEP_STATUS status = ::deliverHandshakeResult(session, partner, |
|||
(sync_handshake_result) result); |
|||
_throw_status(status); |
|||
} |
|||
|
|||
#ifndef NDEBUG |
|||
void SyncMixIn::_inject(int event, Identity partner, object extra) |
|||
{ |
|||
time_t timeout = 0; |
|||
PEP_STATUS status = fsm_DeviceState_inject(session, |
|||
(DeviceState_event) event, partner, NULL, &timeout); |
|||
_throw_status(status); |
|||
} |
|||
#endif |
|||
|
|||
jmp_buf SyncMixIn::env; |
|||
void *SyncMixIn::_msg; |
|||
|
|||
timeout_state_t SyncMixIn::timeout_state = timeout_stopped; |
|||
bool SyncMixIn::last_turn = false; |
|||
time_t SyncMixIn::remaining_time = 0; |
|||
|
|||
int SyncMixIn::inject_sync_msg(void *msg, void *management) |
|||
{ |
|||
assert(timeout_state != timeout_canceling); |
|||
if(timeout_state == timeout_canceling) return 0; |
|||
|
|||
assert(timeout_state != timeout_expiring); |
|||
if(timeout_state == timeout_expiring) return 0; |
|||
|
|||
_msg = msg; |
|||
int val = setjmp(env); |
|||
if (!val){ |
|||
if(timeout_state == timeout_running){ |
|||
// call python timeout timer cancel
|
|||
auto that = dynamic_cast< SyncMixIn_callback * >( |
|||
static_cast< SyncMixIn * > (management)); |
|||
remaining_time = that->cancelTimeout(); |
|||
timeout_state = timeout_canceling; |
|||
} |
|||
last_turn = false; |
|||
do_sync_protocol(session, management); |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
void *SyncMixIn::retrieve_next_sync_msg(void *management, time_t *timeout) |
|||
{ |
|||
if (!last_turn){ |
|||
|
|||
assert(timeout_state != timeout_running); |
|||
if(timeout_state == timeout_running) return NULL; |
|||
|
|||
switch(timeout_state){ |
|||
case timeout_canceling : |
|||
*timeout = remaining_time; |
|||
break; |
|||
case timeout_expiring : |
|||
// "1" is arbitrary value !=0, since we don't
|
|||
// have original timeout value anymore
|
|||
*timeout = 1; |
|||
break; |
|||
default: |
|||
; |
|||
} |
|||
|
|||
timeout_state = timeout_stopped; |
|||
|
|||
last_turn = true; |
|||
return (void *) _msg; |
|||
|
|||
} else { |
|||
|
|||
assert(timeout_state == timeout_stopped); |
|||
if(timeout_state != timeout_stopped) return NULL; |
|||
|
|||
if (*timeout != 0) { |
|||
// call python timeout timer start
|
|||
auto that = dynamic_cast< SyncMixIn_callback * >( |
|||
static_cast< SyncMixIn * > (management)); |
|||
that->setTimeout(*timeout); |
|||
timeout_state = timeout_running; |
|||
} |
|||
} |
|||
longjmp(env, 1); |
|||
return (void *) 23; |
|||
} |
|||
|
|||
// to be called from python timeout timer - may GIL protect us
|
|||
void SyncMixIn::onTimeout(){ |
|||
assert(timeout_state != timeout_canceling); |
|||
if(timeout_state == timeout_canceling) return; |
|||
|
|||
assert(timeout_state != timeout_expiring); |
|||
if(timeout_state == timeout_expiring) return; |
|||
|
|||
_msg = NULL; |
|||
int val = setjmp(env); |
|||
if (!val){ |
|||
timeout_state = timeout_expiring; |
|||
|
|||
last_turn = false; |
|||
do_sync_protocol(session, (void*)this); |
|||
} |
|||
} |
|||
|
|||
void SyncMixIn_callback::messageToSend(Message msg) |
|||
{ |
|||
call_method< void >(_self, "messageToSend", msg); |
|||
} |
|||
|
|||
void SyncMixIn_callback::notifyHandshake( |
|||
Identity me, Identity partner, sync_handshake_signal signal) |
|||
{ |
|||
call_method< void >(_self, "notifyHandshake", me, partner, signal); |
|||
} |
|||
|
|||
void SyncMixIn_callback::setTimeout(time_t timeout) |
|||
{ |
|||
call_method< void >(_self, "setTimeout", timeout); |
|||
} |
|||
|
|||
time_t SyncMixIn_callback::cancelTimeout() |
|||
{ |
|||
return call_method< time_t >(_self, "cancelTimeout"); |
|||
} |
|||
} |
|||
} |
|||
|
@ -1,86 +0,0 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#pragma once |
|||
|
|||
#include "pEpmodule.hh" |
|||
#include <setjmp.h> |
|||
#include <pEp/sync_api.h> |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
|
|||
typedef enum _timeout_state_t { |
|||
timeout_stopped, |
|||
timeout_running, |
|||
timeout_canceling, |
|||
timeout_expiring |
|||
} timeout_state_t; |
|||
|
|||
class SyncMixIn { |
|||
public: |
|||
SyncMixIn() { } |
|||
virtual ~SyncMixIn() { } |
|||
|
|||
virtual void messageToSend(Message msg) { |
|||
throw runtime_error("override this method"); |
|||
} |
|||
|
|||
virtual void notifyHandshake( |
|||
pEp::PythonAdapter::Identity me, |
|||
pEp::PythonAdapter::Identity partner, |
|||
sync_handshake_signal signal) |
|||
{ |
|||
throw runtime_error("override this method"); |
|||
} |
|||
|
|||
virtual void deliverHandshakeResult( |
|||
pEp::PythonAdapter::Identity partner, int result); |
|||
#ifndef NDEBUG |
|||
virtual void _inject( |
|||
int event, |
|||
pEp::PythonAdapter::Identity partner, object extra); |
|||
#endif |
|||
virtual void setTimeout(time_t timeout){ |
|||
throw runtime_error("override this method"); |
|||
} |
|||
|
|||
virtual time_t cancelTimeout(){ |
|||
throw runtime_error("override this method"); |
|||
} |
|||
|
|||
virtual void onTimeout(); |
|||
|
|||
protected: |
|||
static PEP_STATUS _messageToSend(void *obj, message *msg); |
|||
static PEP_STATUS _notifyHandshake(void *obj, |
|||
pEp_identity *me, pEp_identity *partner, sync_handshake_signal signal); |
|||
|
|||
static jmp_buf env; |
|||
static void *_msg; |
|||
static timeout_state_t timeout_state; |
|||
static bool last_turn; |
|||
static time_t remaining_time; |
|||
static int inject_sync_msg(void *msg, void *management); |
|||
static void *retrieve_next_sync_msg(void *management, time_t *timeout); |
|||
}; |
|||
|
|||
class SyncMixIn_callback : public SyncMixIn { |
|||
PyObject* const _self; |
|||
|
|||
public: |
|||
SyncMixIn_callback(PyObject *self); |
|||
~SyncMixIn_callback(); |
|||
|
|||
void messageToSend(Message msg); |
|||
void notifyHandshake( |
|||
pEp::PythonAdapter::Identity me, |
|||
pEp::PythonAdapter::Identity partner, |
|||
sync_handshake_signal signal); |
|||
|
|||
void setTimeout(time_t timeout); |
|||
time_t cancelTimeout(); |
|||
}; |
|||
} |
|||
} |
|||
|
@ -0,0 +1,66 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#include "user_interface.hh" |
|||
#include <assert.h> |
|||
#include <time.h> |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
UserInterface_callback::UserInterface_callback(PyObject *self) : |
|||
_self(self) |
|||
{ |
|||
adapter.ui_object(self); |
|||
PEP_STATUS status = ::register_sync_callbacks(adapter.session(), |
|||
(void *) this, _notifyHandshake, retrieve_next_sync_event); |
|||
assert(status == PEP_STATUS_OK); |
|||
if (status) |
|||
_throw_status(status); |
|||
} |
|||
|
|||
UserInterface_callback::~UserInterface_callback() |
|||
{ |
|||
::unregister_sync_callbacks(adapter.session()); |
|||
} |
|||
|
|||
PEP_STATUS UserInterface::_notifyHandshake(void *obj, |
|||
pEp_identity *me, pEp_identity *partner, |
|||
sync_handshake_signal signal |
|||
) |
|||
{ |
|||
if (!obj) |
|||
return PEP_SEND_FUNCTION_NOT_REGISTERED; |
|||
|
|||
if (!(me && partner)) |
|||
return PEP_ILLEGAL_VALUE; |
|||
|
|||
auto that = dynamic_cast< UserInterface_callback * >( |
|||
static_cast< UserInterface * > (obj)); |
|||
that->notifyHandshake(Identity(me), Identity(partner), signal); |
|||
|
|||
return PEP_STATUS_OK; |
|||
} |
|||
|
|||
void UserInterface::deliverHandshakeResult(Identity partner, |
|||
int result) |
|||
{ |
|||
PEP_STATUS status = ::deliverHandshakeResult(adapter.session(), |
|||
partner, (sync_handshake_result) result); |
|||
_throw_status(status); |
|||
} |
|||
|
|||
SYNC_EVENT UserInterface::retrieve_next_sync_event(void *management) |
|||
{ |
|||
while (adapter.q.empty()) |
|||
nanosleep((const struct timespec[]){{0, 100000000L}}, NULL); |
|||
return adapter.q.pop_front(); |
|||
} |
|||
|
|||
void UserInterface_callback::notifyHandshake( |
|||
Identity me, Identity partner, sync_handshake_signal signal) |
|||
{ |
|||
call_method< void >(_self, "notifyHandshake", me, partner, signal); |
|||
} |
|||
} |
|||
} |
|||
|
@ -0,0 +1,48 @@ |
|||
// This file is under GNU Affero General Public License 3.0
|
|||
// see LICENSE.txt
|
|||
|
|||
#pragma once |
|||
|
|||
#include "pEpmodule.hh" |
|||
#include <setjmp.h> |
|||
#include <pEp/sync_api.h> |
|||
|
|||
namespace pEp { |
|||
namespace PythonAdapter { |
|||
class UserInterface { |
|||
public: |
|||
UserInterface() { } |
|||
virtual ~UserInterface() { } |
|||
|
|||
virtual void notifyHandshake( |
|||
pEp::PythonAdapter::Identity me, |
|||
pEp::PythonAdapter::Identity partner, |
|||
sync_handshake_signal signal) |
|||
{ |
|||
throw runtime_error("override this method"); |
|||
} |
|||
|
|||
virtual void deliverHandshakeResult( |
|||
pEp::PythonAdapter::Identity partner, int result); |
|||
|
|||
protected: |
|||
static PEP_STATUS _notifyHandshake(void *obj, pEp_identity *me, |
|||
pEp_identity *partner, sync_handshake_signal signal); |
|||
static SYNC_EVENT retrieve_next_sync_event( void *management); |
|||
}; |
|||
|
|||
class UserInterface_callback : public UserInterface { |
|||
PyObject *_self; |
|||
|
|||
public: |
|||
UserInterface_callback(PyObject *self); |
|||
~UserInterface_callback(); |
|||
|
|||
void notifyHandshake( |
|||
pEp::PythonAdapter::Identity me, |
|||
pEp::PythonAdapter::Identity partner, |
|||
sync_handshake_signal signal); |
|||
}; |
|||
} |
|||
} |
|||
|
Loading…
Reference in new issue