doSynchronize :: (RaftLog l e v) => Raft l e v -> ((RaftContext l e v) -> AppendEntries e -> IO (RaftContext l e v)) -> (Name -> Bool) -> IO ()
doSynchronize vRaft reqfn contfn = do
    initialRaft <- atomically $ readTVar (raftContext vRaft)
    let endpoint = raftEndpoint initialRaft
        cfg = raftStateConfiguration $ raftState initialRaft
        name = raftName initialRaft
    maybeLeader <- onAppendEntries endpoint cfg name $ \req -> do
        raft <- atomically $ do
            raft <-readTVar (raftContext vRaft)
            if (aeLeaderTerm req) < (raftCurrentTerm raft)
                then return raft
                else do
                    modifyTVar (raftContext vRaft) $ \oldRaft ->
                            setRaftTerm (aeLeaderTerm req)
                                $ setRaftLeader (Just $ aeLeader req)
                                $ setRaftLastCandidate Nothing oldRaft
                    readTVar (raftContext vRaft)
        -- check previous entry for consistency
        let requestPreviousTerm = (logTerm $ aePreviousTime req)
            prevIndex = (logIndex $ aePreviousTime req)
        localPreviousTerm <- if prevIndex < 0
            then return (-1)
            else do
                prevEntries <- fetchEntries (raftLog raft) prevIndex 1
                return $ entryTerm $ head prevEntries
        let valid = requestPreviousTerm == localPreviousTerm
        synchronizedRaft <- if valid
                then reqfn raft req
                else return raft
        return $ mkResult valid synchronizedRaft
    case maybeLeader of
        -- we did hear a message before the timeout, and we have a committed time
        Just leader ->  do
            if contfn leader
                then doSynchronize vRaft reqfn contfn
                else return ()
        Nothing -> return ()
doSynchronize :: (RaftLog l e v) => Raft l e v -> ((RaftContext l e v) -> AppendEntries e -> IO (RaftContext l e v)) -> (Name -> Bool) -> IO ()
doSynchronize vRaft reqfn contfn = do
    initialRaft <- atomically $ readTVar (raftContext vRaft)
    let endpoint = raftEndpoint initialRaft
        cfg = raftStateConfiguration $ raftState initialRaft
        name = raftName initialRaft
    maybeLeader <- onAppendEntries endpoint cfg name $ \req -> do
        raft <- atomically $ do
            raft <-readTVar (raftContext vRaft)
            if (aeLeaderTerm req) < (raftCurrentTerm raft)
                then return raft
                else do
                    modifyTVar (raftContext vRaft) $ \oldRaft ->
                            setRaftTerm (aeLeaderTerm req)
                                $ setRaftLeader (Just $ aeLeader req)
                                $ setRaftLastCandidate Nothing oldRaft
                    readTVar (raftContext vRaft)
        -- check previous entry for consistency
        let requestPreviousTerm = (logTerm $ aePreviousTime req)
            prevIndex = (logIndex $ aePreviousTime req)
        localPreviousTerm <- if prevIndex < 0
            then return (-1)
            else do
                prevEntries <- fetchEntries (raftLog raft) prevIndex 1
                return $ entryTerm $ head prevEntries
        let valid = requestPreviousTerm == localPreviousTerm
        synchronizedRaft <- if valid
                then reqfn raft req
                else return raft
        return $ mkResult valid synchronizedRaft
    case maybeLeader of
        -- we did hear a message before the timeout, and we have a committed time
        Just leader ->  do
            if contfn leader
                then doSynchronize vRaft reqfn contfn
                else return ()
        Nothing -> return ()
doSynchronize vRaft reqfn contfn = do
    initialRaft <- atomically $ readTVar (raftContext vRaft)
    let endpoint = raftEndpoint initialRaft
        cfg = raftStateConfiguration $ raftState initialRaft
        name = raftName initialRaft
    maybeLeader <- onAppendEntries endpoint cfg name $ \req -> do
        raft <- atomically $ do
            raft <-readTVar (raftContext vRaft)
            if (aeLeaderTerm req) < (raftCurrentTerm raft)
                then return raft
                else do
                    modifyTVar (raftContext vRaft) $ \oldRaft ->
                            setRaftTerm (aeLeaderTerm req)
                                $ setRaftLeader (Just $ aeLeader req)
                                $ setRaftLastCandidate Nothing oldRaft
                    readTVar (raftContext vRaft)
        -- check previous entry for consistency
        let requestPreviousTerm = (logTerm $ aePreviousTime req)
            prevIndex = (logIndex $ aePreviousTime req)
        localPreviousTerm <- if prevIndex < 0
            then return (-1)
            else do
                prevEntries <- fetchEntries (raftLog raft) prevIndex 1
                return $ entryTerm $ head prevEntries
        let valid = requestPreviousTerm == localPreviousTerm
        synchronizedRaft <- if valid
                then reqfn raft req
                else return raft
        return $ mkResult valid synchronizedRaft
    case maybeLeader of
        -- we did hear a message before the timeout, and we have a committed time
        Just leader ->  do
            if contfn leader
                then doSynchronize vRaft reqfn contfn
                else return ()
        Nothing -> return ()