Example #1
0
int GUIAPI PostSyncMessage (HWND hWnd, int msg, WPARAM wParam, LPARAM lParam)
{
    MG_CHECK_RET (MG_IS_WINDOW(hWnd), -1);
    if (BE_THIS_THREAD(hWnd))
        return -1;

    return SendSyncMessage (hWnd, msg, wParam, lParam);
}
Example #2
0
int GUIAPI SendMessage (HWND hWnd, int iMsg, WPARAM wParam, LPARAM lParam)
{
    WNDPROC WndProc;

    MG_CHECK_RET (MG_IS_WINDOW(hWnd), -1);

#ifndef _LITE_VERSION
    if (!BE_THIS_THREAD(hWnd))
        return SendSyncMessage (hWnd, iMsg, wParam, lParam);
#endif /* !_LITE_VERSION */
    
    if ( !(WndProc = GetWndProc(hWnd)) )
        return ERR_INV_HWND;

    return (*WndProc)(hWnd, iMsg, wParam, lParam);

}
void SyncManagerImpl::Update()
{
	PROFILE_SCOPE("SyncManager Update");

	const OperationList& appliedOpList = m_syncContext->GetAppliedOperations();

	// Add all the locally applied changes to the outgoing queue of the remote peers
	if (!appliedOpList.empty())
	{
		for (size_t i = 0; i < appliedOpList.size(); ++i)
		{
			for (size_t j = 0; j < m_remoteHosts.size(); ++j)
			{
				RemoteSyncPeer& currentHost = m_remoteHosts[j];

				if (currentHost.m_bHandshakeComplete && currentHost.m_bHasAddedStartingState)
				{
					currentHost.SendOp(appliedOpList[i]);
				}
			}
		}

		// Clear out the list of locally applied operations
		m_syncContext->ClearAppliedOperations();
	}


	// Check to see if any new remote peers have connected since the last sync, and if so
	// add create operation for each element in our list to their outgoing queue
	for (size_t hostIndex = 0; hostIndex < m_remoteHosts.size(); ++hostIndex)
	{
		RemoteSyncPeer& currentHost = m_remoteHosts[hostIndex];

		if (currentHost.m_bHandshakeComplete && !currentHost.m_bHasAddedStartingState)
		{
#if defined(SYNC_DEBUG)
			LogInfo("%s Sending Deltas", m_syncContext->GetLocalUser()->GetName().GetString().c_str());
#endif
			// Check that the deltas are the first ops we are sending to the remote client
			XTASSERT(currentHost.m_localState.m_opsSent == 0);
			XTASSERT(currentHost.m_outgoing.empty());
			XTASSERT(currentHost.m_sendList.empty());

			AddCreateOpForElementRecurs(currentHost, m_syncContext->GetRootObject());
			currentHost.m_bHasAddedStartingState = true;
		}
	}

	
	const TransformManager& transfromMgr = m_syncContext->GetTransformManager();

	// Loop through all the incoming remote changes
	for (size_t hostIndex = 0; hostIndex < m_remoteHosts.size(); ++hostIndex)
	{
		RemoteSyncPeer& currentHost = m_remoteHosts[hostIndex];

		if (currentHost.m_bHandshakeComplete)
		{
			VersionedOpList& incomingOpList = currentHost.m_incoming;
			VersionedOpList& outgoingOpList = currentHost.m_outgoing;

			// For each incoming operation
			for (VersionedOpList::iterator opIt = incomingOpList.begin(); opIt != incomingOpList.end(); ++opIt)
			{
				VersionedOp& remoteMsg = *opIt;

				// Debugging hack
				if (remoteMsg.m_state.m_opsSent == 0)
				{
					// The first op we get should be a catch-up data create of the root
					XTASSERT(remoteMsg.m_op->GetType() == Operation::Create && remoteMsg.m_op->GetTargetGuid() == m_syncContext->GetRootObject()->GetGUID());
				}

#if defined(SYNC_DEBUG)
				LogInfo("%s received op (%s) from %s, version %i %i", m_syncContext->GetLocalUser()->GetName().GetString().c_str(), remoteMsg.m_op->GetOpDescription().c_str(), currentHost.m_userName.c_str(), remoteMsg.m_state.m_opsSent, remoteMsg.m_state.m_opsReceived);	
#endif

				// Discard the acknowledged operations, we don't need to transform against them anymore
				while (!outgoingOpList.empty() && outgoingOpList.front().m_state.m_opsSent < remoteMsg.m_state.m_opsReceived)
				{
#if defined(SYNC_DEBUG)
					LogInfo("  Invalidating %s op, version %i %i", outgoingOpList.front().m_op->GetTypeName(), outgoingOpList.front().m_state.m_opsSent, outgoingOpList.front().m_state.m_opsReceived);
#endif
					outgoingOpList.erase(outgoingOpList.begin());
				}

				if (remoteMsg.m_op->GetType() != Operation::Ack)
				{
					// Ensure that our starting state is the same as the one the message was sent from
					XTASSERT(remoteMsg.m_state.m_opsSent == currentHost.m_localState.m_opsReceived);

					// Transform the incoming ops by the changes that have not yet been acknowledged by the remote host
					for (VersionedOpList::iterator outgoingOpIt = outgoingOpList.begin(); outgoingOpIt != outgoingOpList.end(); ++outgoingOpIt)
					{
						VersionedOp& localMsg = *outgoingOpIt;

						TransformedPair transformResult = transfromMgr.Transform(localMsg.m_op, remoteMsg.m_op);

						localMsg.m_op = transformResult.m_localOpTransformed;
						remoteMsg.m_op = transformResult.m_remoteOpTransformed;

						// Early-out of the loop if the op was rendered invalid by the transformation
						if (remoteMsg.m_op->GetType() == Operation::Noop)
						{
							break;
						}
					}

					if (remoteMsg.m_op->GetType() != Operation::Noop)
					{
						// Const-cast so that we can apply the operation and change the auth level.  
						// All the rest of the code uses const for safety, as the ops should not change except when applied
						OperationPtr clonedOp = const_cast<Operation*>(remoteMsg.m_op.get());

						// Apply the transformed ops to the local data set
						clonedOp->Apply(m_syncContext);

						// Now that the op has been applied locally, it is set to the local system's authority level before
						// being queued to be passed to the other systems
						clonedOp->SetAuthorityLevel(m_syncContext->GetAuthorityLevel());

						// Add the op to the list of changes applied this Sync so that we can notify the listeners when all changes have been applied
						m_pendingNotifications.push(clonedOp);

						// Add the transformed op to the outgoing list for the other hosts
						for (size_t otherHostIndex = 0; otherHostIndex < m_remoteHosts.size(); ++otherHostIndex)
						{
							if (otherHostIndex != hostIndex)
							{
								RemoteSyncPeer& otherHost = m_remoteHosts[otherHostIndex];
								if (otherHost.m_bHandshakeComplete && otherHost.m_bHasAddedStartingState)
								{
									otherHost.SendOp(clonedOp);
								}
							}
						}
					}

					++currentHost.m_localState.m_opsReceived;
				}

				// Record what we know of the state of the remote machine
				currentHost.m_remoteState = remoteMsg.m_state;
			}

			incomingOpList.clear();
		}
	}

	// Send the changes in each remotePeer's outgoing op list.  
	// Nothing will be sent if the last message was not acknowledged.  
	for (size_t hostIndex = 0; hostIndex < m_remoteHosts.size(); ++hostIndex)
	{
		SendSyncMessage(m_remoteHosts[hostIndex]);
	}

	// Notify listeners about the remote changes
	if (!m_pendingNotifications.empty())
	{
		if (m_listener)
		{
			try
			{
				m_listener->OnSyncChangesBegin();
			}
			catch (...)
			{
				LogError("Exception occurred during OnSyncChangesBegin callback");
			}
		}

		while (!m_pendingNotifications.empty())
		{
			OperationPtr currentOp = m_pendingNotifications.front();

			try
			{
				currentOp->Notify(m_syncContext);
			}
			catch (...)
			{
				LogError("Exception occurred during Sync notification callback");
			}

			m_pendingNotifications.pop();
		}

		if (m_listener)
		{
			try
			{
				m_listener->OnSyncChangesEnd();
			}
			catch (...)
			{
				LogError("Exception occurred during OnSyncChangesEnd callback");
			}
		}
	}
}