void AbiCollab::addCollaborator(BuddyPtr pCollaborator)
{
    UT_DEBUGMSG(("AbiCollab::addCollaborator()\n"));
    UT_return_if_fail(pCollaborator)

    // check if this buddy is in the access control list if we are hosting
    // this session
    if (isLocallyControlled())
    {
        AccountHandler* pAccount = pCollaborator->getHandler();
        UT_return_if_fail(pAccount);
        if (!pAccount->hasAccess(m_vAcl, pCollaborator))
        {
            UT_ASSERT(UT_NOT_IMPLEMENTED);
            return;
        }
    }

    // check for duplicates (as long as we assume a collaborator can only be part of a collaboration session once)
    std::map<BuddyPtr, std::string>::iterator it = m_vCollaborators.find(pCollaborator);
    if (it != m_vCollaborators.end())
    {
        UT_DEBUGMSG(("Attempting to add buddy '%s' twice to a collaboration session!", pCollaborator->getDescription().utf8_str()));
        UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
        return;
    }

    m_vCollaborators[pCollaborator] = ""; // will fill the remote document UUID later once we receive a packet from this buddy
}
void AbiCollabSessionManager::disjoinSession(const UT_UTF8String& sSessionId)
{
	UT_DEBUGMSG(("AbiCollabSessionManager::disjoinSession(%s)\n", sSessionId.utf8_str()));

	AbiCollab* pSession = getSessionFromSessionId(sSessionId);
	UT_return_if_fail(pSession);
	
	const std::map<BuddyPtr, std::string> vCollaborators = pSession->getCollaborators();

	if (!isLocallyControlled(pSession->getDocument()))
	{		
		// we are joined to a session, so there should only be one collaborator:
		// the person sharing the document
		UT_return_if_fail(vCollaborators.size() == 1);
		
		std::map<BuddyPtr, std::string>::const_iterator cit = vCollaborators.begin();
		BuddyPtr pCollaborator = (*cit).first;
		destroySession(pSession);
			
		DisjoinSessionEvent event(sSessionId);
		event.addRecipient(pCollaborator);
		signal(event);
	}
	else
	{
		UT_ASSERT(UT_NOT_REACHED);
		return;
	}
}
void AbiCollabSessionManager::disconnectSession(AbiCollab* pSession)
{
	UT_return_if_fail(pSession);
	UT_DEBUGMSG(("AbiCollabSessionManager::disconnectSession() - pSession: %s\n", pSession->getSessionId().utf8_str()));

	if (isLocallyControlled(pSession->getDocument()))
	{
		/* 
		Before we close this session, try to see of we can hand over
		session ownership to someone else.

		NOTE: we don't do any fancy determination yet who to hand over the
		session to; we just hand it over to the first buddy in the list.
		*/
		if (_canInitiateSessionTakeover(pSession))
		{
			UT_DEBUGMSG(("Can initiate session takeover\n"));

			if (pSession->getCollaborators().size() > 0)
			{
				std::map<BuddyPtr, std::string>::const_iterator cit = pSession->getCollaborators().begin();
				pSession->initiateSessionTakeover((*cit).first);
			}
		}

		closeSession(pSession, false);
	}
	else
	{
		disjoinSession(pSession->getSessionId());
	}
	// TODO: mark the session as disconnected/closed, for additional safety
}
/*!
 *	Send this packet. Note, the specified packet does still belong to the calling class.
 *	So if we want to store it (for masking), we HAVE to clone it first
 */
void AbiCollab::push(SessionPacket* pPacket)
{
    UT_DEBUGMSG(("AbiCollab::push()\n"));
    UT_return_if_fail(pPacket);

    if (m_bIsReverting)
    {
        UT_DEBUGMSG(("This packet was generated by a local revert triggerd in the import; dropping on the floor!\n"));
        return;
    }

    if (m_bExportMasked)
    {
        m_vecMaskedPackets.push_back(static_cast<SessionPacket*>(pPacket->clone())); // TODO: make this a shared ptr, so we don't need to clone the packet
        return;
    }

    if (!isLocallyControlled() && m_eTakeoveState != STS_NONE)
    {
        // TODO: revert ack packets should still go to old master
        // (or be dropped on the floor, as he probably is not even around anymore)
        UT_DEBUGMSG(("We're in the middle of a session takeover; holding on to the packet until the new master is ready"));
        m_vOutgoingQueue.push_back(static_cast<SessionPacket*>(pPacket->clone())); // TODO: make this a shared ptr, so we don't need to clone the packet
        return;
    }

    // record
    if (m_pRecorder)
        m_pRecorder->storeOutgoing( const_cast<const SessionPacket*>( pPacket ) );

    // TODO: this could go in the session manager
    UT_DEBUGMSG(("Pusing packet to %d collaborators\n", m_vCollaborators.size()));
    for (std::map<BuddyPtr, std::string>::iterator it = m_vCollaborators.begin(); it != m_vCollaborators.end(); it++)
    {
        BuddyPtr pCollaborator = (*it).first;
        UT_continue_if_fail(pCollaborator);

        UT_DEBUGMSG(("Pushing packet to collaborator with descriptor: %s\n", pCollaborator->getDescriptor(true).utf8_str()));
        AccountHandler* pHandler = pCollaborator->getHandler();
        UT_continue_if_fail(pHandler);

        // overwrite remote revision for this collaborator
        _fillRemoteRev(pPacket, pCollaborator);

        // send!
        bool res = pHandler->send(pPacket, pCollaborator);
        if (!res)
        {
            UT_DEBUGMSG(("Error sending a packet!\n"));
        }
    }
}
void AbiCollab::_checkRevokeAccess(BuddyPtr pCollaborator)
{
    UT_DEBUGMSG(("AbiCollab::_checkRevokeAccess()\n"));
    UT_return_if_fail(pCollaborator);
    UT_return_if_fail(isLocallyControlled());
    UT_return_if_fail(m_pAclAccount);

    // remove this buddy from the access control list if his access rights
    // are not persistent
    if (!pCollaborator->getHandler()->hasPersistentAccessControl())
    {
        for (std::vector<std::string>::iterator it = m_vAcl.begin(); it != m_vAcl.end(); it++)
        {
            if (pCollaborator->getDescriptor(false) == (*it))
            {
                UT_DEBUGMSG(("Dropping %s from the ACL\n", (*it).c_str()));
                m_vAcl.erase(it);
                break;
            }
        }
    }
}
void AbiCollab::startRecording( SessionRecorderInterface* pRecorder )
{
    UT_return_if_fail(pRecorder);

    const UT_GenericVector<ChangeAdjust *>* pExpAdjusts = m_Export.getAdjusts();
    UT_return_if_fail(pExpAdjusts);

    // FIXME: fill this properly
    UT_sint32 iAuthorId = -1;
    UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);

    // create initial document packet to recorder
    // so the recorder knows the initial state
    // serialize entire document into string
    JoinSessionRequestResponseEvent jsre(getSessionId(), iAuthorId);
    if (AbiCollabSessionManager::serializeDocument(m_pDoc, jsre.m_sZABW, false /* no base64 */) == UT_OK)
    {
        // set more document properties
        if (!isLocallyControlled())
        {
            UT_ASSERT_HARMLESS(pExpAdjusts->getItemCount() > 0);
            jsre.m_iRev = (pExpAdjusts->getItemCount() > 0 ? pExpAdjusts->getNthItem(pExpAdjusts->getItemCount()-1)->getLocalRev() : 0);
        }
        else
            jsre.m_iRev = m_pDoc->getCRNumber();
        jsre.m_sDocumentId = m_pDoc->getDocUUIDString();
        if (m_pDoc->getFilename())
            jsre.m_sDocumentName = UT_go_basename_from_uri(m_pDoc->getFilename());

        // store pointer
        m_pRecorder = pRecorder;
        m_pRecorder->storeOutgoing( &jsre );
    }
    else
    {
        UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
    }
}
Esempio n. 7
0
/**
 *  input_ is available only on server or on the local client, not for
 *  remote tanks.
 */
void Tank::frameMove(float dt)
{
    PROFILE(Tank::frameMove);

    setSleeping(false);
    Controllable::frameMove(dt);

    // Weapon firing code is handled on client for local player only
    // to have immediate feedback. Remote players receive weapon
    // feedback by received state.
    bool firing = false;
    if (getLocation() == CL_SERVER_SIDE ||
        (getLocation() == CL_CLIENT_SIDE && isLocallyControlled()))
    {
        firing |= weapon_system_[0]->handleInput(input_.fire1_);
        firing |= weapon_system_[1]->handleInput(input_.fire2_);
        firing |= weapon_system_[2]->handleInput(input_.fire3_);
        firing |= weapon_system_[3]->handleInput(input_.fire4_);
    }

    if (getLocation() != CL_REPLAY_SIM)
    {
        for(unsigned w=0; w < NUM_WEAPON_SLOTS; w++)
        {
            weapon_system_[w]->frameMove(dt);
        }
    }
    
    

    if (is_locally_controlled_ && getLocation() == CL_CLIENT_SIDE)
    {
        frameMoveTurret(dt, true);
    }
    frameMoveTurret(dt, false);

    
    if (is_locally_controlled_ || getLocation() == CL_SERVER_SIDE)
    {
        // remote tanks don't have accurate wheel info, and no extra
        // dampening needed anyway
        handleExtraDampening();
        
        // Don't calc tire physics for uncontrolled objects on client.
        frameMoveTires(dt);
    }

    
    if (location_ == CL_SERVER_SIDE)
    {
        /// heal logic
        if (!firing &&
            params_.get<bool>("tank.heal_skill") &&
            getGlobalLinearVel().length() < s_params.get<float>("server.logic.tank_heal_velocity_threshold") &&
            getOwner() != UNASSIGNED_SYSTEM_ADDRESS)
        {
            startHealing();
        } else
        {
            stopHealing();
        }

        // object is positioned by visual on client side. Avoid redundant
        // positioning
        positionCarriedObject();
        
        if (firing)
        {
            setInvincible(false);
        }
    }
}
void AbiCollab::import(SessionPacket* pPacket, BuddyPtr collaborator)
{
    UT_DEBUGMSG(("AbiCollab::import()\n"));
    UT_return_if_fail(pPacket);

    if (m_bDoingMouseDrag)
    {
        // we block incoming packets while dragging the mouse; this prevents
        // scary race conditions from occuring, like importing a 'delete image' packet
        // when you are just dragging said image around
        UT_DEBUGMSG(("We are currently dragging something around; deferring packet import until after the release!\n"));
        m_vIncomingQueue.push_back(
            std::make_pair(static_cast<SessionPacket*>(pPacket->clone()), collaborator));
        return;
    }

    // record the incoming packet
    if (m_pRecorder)
        m_pRecorder->storeIncoming(pPacket, collaborator);

    // execute an alternative packet handling path when this session is being
    // taken over by another collaborator
    if (AbstractSessionTakeoverPacket::isInstanceOf(*pPacket))
    {
        AbstractSessionTakeoverPacket* astp = static_cast<AbstractSessionTakeoverPacket*>(pPacket);
        bool res = _handleSessionTakeover(astp, collaborator);
        if (!res)
        {
            // TODO: implement/handle an offending collaborator
            UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
        }
        return;
    }

    /*
    Session packets are only allowed to come in from a collaborator when:

    1. no session takeover is in progress, or
    2a. if this session is a slave: always
    2b. if this session is a master: until the collaborator has responded to a
    	SessionTakeoverRequest from us with a SessionTakeoverAck packet
    */

    // TODO: implement/handle an offending collaborator
    UT_return_if_fail(
        (m_eTakeoveState == STS_NONE) ||
        (!isLocallyControlled()) ||
        (isLocallyControlled() && m_eTakeoveState == STS_SENT_TAKEOVER_REQUEST && !_hasAckedSessionTakeover(collaborator))
    );

    // import the packet; note that it might be denied due to collisions
    maskExport();
    if (AbstractChangeRecordSessionPacket::isInstanceOf(*pPacket))
        m_pActivePacket = static_cast<const AbstractChangeRecordSessionPacket*>(pPacket);
    m_vCollaborators[collaborator] = pPacket->getDocUUID().utf8_str(); // FIXME: this is redunant after we set this the first time
    m_Import.import(*pPacket, collaborator);
    m_pActivePacket = NULL;
    const std::vector<SessionPacket*>& maskedPackets = unmaskExport();

    if (isLocallyControlled() && maskedPackets.size() > 0)
    {
        UT_DEBUGMSG(("Forwarding message (%u packets) from %s\n", maskedPackets.size(), collaborator->getDescription().utf8_str()));

        // It seems we are in the center of a collaboration session.
        // It's our duty to reroute the packets to the other collaborators
        for (std::map<BuddyPtr, std::string>::iterator it = m_vCollaborators.begin(); it != m_vCollaborators.end(); it++)
        {
            // send all masked packets during import to everyone, except to the
            // person who initialy sent us the packet
            BuddyPtr pBuddy = (*it).first;
            UT_continue_if_fail(pBuddy);
            if (pBuddy != collaborator)
            {
                UT_DEBUGMSG(("Forwarding message from %s to %s\n", collaborator->getDescription().utf8_str(), pBuddy->getDescription().utf8_str()));
                for (std::vector<SessionPacket*>::const_iterator cit = maskedPackets.begin(); cit != maskedPackets.end(); cit++)
                {
                    SessionPacket* maskedPacket = (*cit);
                    push(maskedPacket, pBuddy);
                }
            }
        }
    }
}
bool AbiCollabSessionManager::processPacket(AccountHandler& /*handler*/, Packet* packet, BuddyPtr buddy) 
{
	UT_DEBUGMSG(("AbiCollabSessionManager::processPacket()\n"));
	UT_return_val_if_fail(packet, false);
	UT_return_val_if_fail(buddy, false);
	
	// check if this is a simple import-meh-now-packet
	PClassType pct = packet->getClassType();
	if (pct >= _PCT_FirstSessionPacket && pct <= _PCT_LastSessionPacket)
	{
		// lookup session
		SessionPacket* dsp = static_cast<SessionPacket*>( packet );
		const UT_UTF8String& sessionId = dsp->getSessionId();
		AbiCollab* pAbiCollab = getSessionFromSessionId(sessionId);
		if (!pAbiCollab) {
			UT_DEBUGMSG(("Unknown session id: '%s'", sessionId.utf8_str()));
			UT_return_val_if_fail(pAbiCollab, true);
		}
		
		// handle packet!
		pAbiCollab->import(dsp, buddy);
		return true;
	}


	// handle packet
	switch (pct) {
		case PCT_StartSessionEvent:
		{
			StartSessionEvent event;
			event.setBroadcast(true);
			signal(event, buddy);
			return true;
		}
		
		case PCT_JoinSessionEvent:
		{
			JoinSessionEvent* jse = static_cast<JoinSessionEvent*>(packet);
			const UT_UTF8String& joinedSessionId = jse->getSessionId();
			
			// someone who joined this session disconnected, remove him from the collaboration session
			AbiCollab* pSession = getSessionFromSessionId(joinedSessionId);			
			if (pSession)
			{		
				if (isLocallyControlled( pSession->getDocument() ))
				{
					// we should already know this buddy, as we sent should have already added this
					// buddy when responding to his JoinSessionRequest
					// TODO: check this
				}

				// signal all
				JoinSessionEvent event(joinedSessionId);
				signal( event, buddy );				
			}
			else
			{
				// we don't know this session, don't forward the packet
				UT_ASSERT_HARMLESS(UT_NOT_REACHED);			
			}
			return true;
		}
		
		case PCT_DisjoinSessionEvent:
		{
			DisjoinSessionEvent* dse = static_cast<DisjoinSessionEvent*>(packet);
			const UT_UTF8String& disjoinedSessionId = dse->getSessionId();
		
			// someone who joined this session disconnected, remove him from the collaboration session
			AbiCollab* pSession = getSessionFromSessionId(disjoinedSessionId);			
			if (pSession)
			{
				pSession->removeCollaborator(buddy);
				
				// signal all 
				DisjoinSessionEvent event(disjoinedSessionId);
				signal(event, buddy);
			}
			else
			{
				// we don't know this session, don't forward the packet
				UT_ASSERT_HARMLESS(UT_NOT_REACHED);
			}
			return true;
		}
		
		case PCT_CloseSessionEvent:
		{
			CloseSessionEvent* cse = static_cast<CloseSessionEvent*>(packet);
			const UT_UTF8String& destroyedSessionId = cse->getSessionId();
		
			buddy->destroyDocHandle( destroyedSessionId );
			
			// handle the event outselves
			AbiCollab* pSession = getSessionFromSessionId(destroyedSessionId);
			if (pSession)
			{
				if (!isLocallyControlled(pSession->getDocument()))
				{
					std::string docName = pSession->getDocument()->getFilename();
					if (docName == "")
						docName = "Untitled"; // TODO: fetch the title from the frame somehow (which frame?) - MARCM
					
					// the server hosting this session is gone, so let's disconnect as well
					if (!destroySession(pSession))
					{
						UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
					}

					// signal all 
					CloseSessionEvent event( destroyedSessionId );
					signal( event, buddy );

					// inform the user of the disconnect			
					XAP_Frame *pFrame = XAP_App::getApp()->getLastFocussedFrame();
					UT_return_val_if_fail(pFrame, true);
					UT_UTF8String msg;
					// TODO: make this localizable
					UT_UTF8String_sprintf(msg, "Document %s is not being shared anymore by buddy %s. You are disconnected from the collaboration session.", docName.c_str(), buddy->getDescription().utf8_str());
					pFrame->showMessageBox(msg.utf8_str(), XAP_Dialog_MessageBox::b_O, XAP_Dialog_MessageBox::a_OK);
				}
				else
				{
					// someone who is not controlling this session sends out messages he closed it!
					// we will not forward this packet
					UT_ASSERT_HARMLESS(UT_NOT_REACHED);
				}
			}
			else
            {
				UT_DEBUGMSG(("Ignoring a CloseSession event for unknown session (%s)\n", destroyedSessionId.utf8_str()));
            }
			return true;
		}
		
		case PCT_AccountAddBuddyRequestEvent:
		{
			// look at this packet; I have a feeling we need to deprecate it - MARCM
			UT_ASSERT_HARMLESS(UT_NOT_IMPLEMENTED);
			return true;
		}
		
		default:
			break;
	}

	return false;
}