#include #include using namespace std; class SessionCallbackAdapter : public MWMapCallbackAdapter, public enable_shared_from_this { public: SessionCallbackAdapter(const shared_ptr& callback, const shared_ptr& session, bool trace, const shared_ptr& logger, const std::string& name) : _callback(callback), _session(session), _trace(trace), _logger(logger), _name(name) { } void init(Ice::StringSeq users) override { auto self = shared_from_this(); try { _callback->initAsync(users, nullptr, [self](std::exception_ptr eptr) { self->failed(eptr); }); } catch(const Ice::CommunicatorDestroyedException&) { // Ignored server is being shutdown } } void join(const shared_ptr& e) override { auto self = shared_from_this(); try { _callback->joinAsync(e->timestamp, e->name, nullptr, [self](exception_ptr eptr) { self->failed(eptr); }); } catch(const Ice::CommunicatorDestroyedException&) { // Ignored server is being shutdown } } void leave(const shared_ptr& e) override { auto self = shared_from_this(); try { _callback->leaveAsync(e->timestamp, e->name, nullptr, [self](exception_ptr eptr) { self->failed(eptr); }); } catch(const Ice::CommunicatorDestroyedException&) { // Ignored server is being shutdown } } void send(const shared_ptr& e) override { auto self = shared_from_this(); try { _callback->sendAsync(e->timestamp, e->name, e->message, nullptr, [self](exception_ptr eptr) { self->failed(eptr); }); } catch(const Ice::CommunicatorDestroyedException&) { // Ignored server is being shutdown } } void failed(exception_ptr) { if(_trace) { Ice::Trace out(_logger, "info"); out << "Error sending request to user '" << _name << "'. The user's session will be destroyed."; } try { _session->ice_endpoints(Ice::EndpointSeq())->destroy(); // Collocated call. } catch(const Ice::LocalException&) { } } private: const shared_ptr _callback; const shared_ptr _session; const bool _trace; const shared_ptr _logger; const string _name; }; MWSessionI::MWSessionI(const shared_ptr& MWMap, const string& name, bool trace, const shared_ptr& logger) : _MWMap(MWMap), _name(name), _trace(trace), _logger(logger) { } void MWSessionI::setCallback(shared_ptr callback, const Ice::Current& current) { lock_guard sync(_mutex); if(_destroy) { if(_trace) { Ice::Trace out(_logger, "info"); out << "User '" << _name << "' tried to set the session callback but the session is already destroyed."; } throw Ice::ObjectNotExistException(__FILE__, __LINE__); } if(_callback || !callback) { return; } Ice::Context ctx; ctx["_fwd"] = "o"; _callback = make_shared( callback->ice_context(ctx), Ice::uncheckedCast(current.adapter->createProxy(current.id)), _trace, _logger, _name); _MWRoom->join(_name, _callback); } long long MWSessionI::send(string message, const Ice::Current&) { lock_guard sync(_mutex); if(_destroy) { if(_trace) { Ice::Trace out(_logger, "info"); out << "User '" << _name << "' tried to send a message but the session is already destroyed."; } throw Ice::ObjectNotExistException(__FILE__, __LINE__); } if(!_callback) { if(_trace) { Ice::Trace out(_logger, "info"); out << "User '" << _name << "' tried to send a message without setting the callback."; } throw MW::InvalidMessageException("You cannot send messages until you join the MW Map."); } string msg; try { msg = validateMessage(message); } catch(const exception& ex) { if(_trace) { Ice::Trace out(_logger, "info"); out << "User '" << _name << "' sent an invalid message:\n" << ex; } throw MW::InvalidMessageException(ex.what()); } return _MWMap->send(_name, move(msg)); } void MWSessionI::destroy(const Ice::Current& current) { lock_guard sync(_mutex); if(_destroy) { if(_trace) { Ice::Trace out(_logger, "info"); out << "Trying to destroy the session for user '" << _name << "' but the session is already destroyed."; } throw Ice::ObjectNotExistException(__FILE__, __LINE__); } try { current.adapter->remove(current.id); if(_callback) { _MWMap->leave(_name); } else { _MWMap->unreserve(_name); } } catch(const Ice::ObjectAdapterDeactivatedException&) { // No need to clean up, the server is shutting down. } if(_trace) { Ice::Trace out(_logger, "info"); out << "Push session for user '" << _name << "' destroyed."; } _destroy = true; }