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); }
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"); } } } }