doVote :: (RaftLog l e v) => Raft l e v -> IO ()
doVote vRaft = do
    initialRaft <- atomically $ readTVar (raftContext vRaft)
    let endpoint = raftEndpoint initialRaft
        cfg = raftStateConfiguration $ raftState initialRaft
        name = raftName initialRaft
        leading = (Just name) == (clusterLeader $ clusterConfiguration cfg)
    votedForCandidate <- onRequestVote endpoint name $ \req -> do
        debugM _log $ printf "Server %v received vote request from %v" name (show $ rvCandidate req)
        (raft,vote,reason) <- atomically $ do
            raft <- readTVar (raftContext vRaft)
            let log = raftLog raft
            if (rvCandidateTerm req) < (raftCurrentTerm raft)
                then return (raft,False,"Candidate term too old")
                else do
                    modifyTVar (raftContext vRaft) $ \oldRaft -> setRaftTerm (rvCandidateTerm req) oldRaft
                    case raftStateLastCandidate $ raftState raft of
                        Just candidate -> do
                            if (candidate == rvCandidate req)
                                then return (raft,True,"Candidate already seen")
                                else return (raft,False,"Already saw different candidate")
                        Nothing -> do
                            modifyTVar (raftContext vRaft) $ \oldRaft ->
                                    setRaftLastCandidate (Just $ rvCandidate req) oldRaft
                            if name == rvCandidate req
                                then return (raft,True,"Voting for self")
                                else do
                                    if (rvCandidateLastEntryTime req) >= (lastAppendedTime log)
                                        then do
                                            modifyTVar (raftContext vRaft) $ \oldRaft -> 
                                                setRaftLastCandidate (Just $ rvCandidate req) oldRaft
                                            return (raft,True,"Candidate log more up to date")
                                        else return (raft,False,"Candidate log out of date")
        infoM _log $ printf "Server %v vote for %v is %v because %v" name (rvCandidate req) (show (raftCurrentTerm raft,vote)) reason
        return $ mkResult vote raft
    if leading && votedForCandidate
        then return ()
        else doVote vRaft

{-|
Initiate an election, volunteering to lead the cluster if elected.
-}
doVote :: (RaftLog l e v) => Raft l e v -> IO ()
doVote vRaft = do
    initialRaft <- atomically $ readTVar (raftContext vRaft)
    let endpoint = raftEndpoint initialRaft
        cfg = raftStateConfiguration $ raftState initialRaft
        name = raftName initialRaft
        leading = (Just name) == (clusterLeader $ clusterConfiguration cfg)
    votedForCandidate <- onRequestVote endpoint name $ \req -> do
        debugM _log $ printf "Server %v received vote request from %v" name (show $ rvCandidate req)
        (raft,vote,reason) <- atomically $ do
            raft <- readTVar (raftContext vRaft)
            let log = raftLog raft
            if (rvCandidateTerm req) < (raftCurrentTerm raft)
                then return (raft,False,"Candidate term too old")
                else do
                    modifyTVar (raftContext vRaft) $ \oldRaft -> setRaftTerm (rvCandidateTerm req) oldRaft
                    case raftStateLastCandidate $ raftState raft of
                        Just candidate -> do
                            if (candidate == rvCandidate req)
                                then return (raft,True,"Candidate already seen")
                                else return (raft,False,"Already saw different candidate")
                        Nothing -> do
                            modifyTVar (raftContext vRaft) $ \oldRaft ->
                                    setRaftLastCandidate (Just $ rvCandidate req) oldRaft
                            if name == rvCandidate req
                                then return (raft,True,"Voting for self")
                                else do
                                    if (rvCandidateLastEntryTime req) >= (lastAppendedTime log)
                                        then do
                                            modifyTVar (raftContext vRaft) $ \oldRaft -> 
                                                setRaftLastCandidate (Just $ rvCandidate req) oldRaft
                                            return (raft,True,"Candidate log more up to date")
                                        else return (raft,False,"Candidate log out of date")
        infoM _log $ printf "Server %v vote for %v is %v because %v" name (rvCandidate req) (show (raftCurrentTerm raft,vote)) reason
        return $ mkResult vote raft
    if leading && votedForCandidate
        then return ()
        else doVote vRaft

{-|
Initiate an election, volunteering to lead the cluster if elected.
-}
doVote vRaft = do
    initialRaft <- atomically $ readTVar (raftContext vRaft)
    let endpoint = raftEndpoint initialRaft
        cfg = raftStateConfiguration $ raftState initialRaft
        name = raftName initialRaft
        leading = (Just name) == (clusterLeader $ clusterConfiguration cfg)
    votedForCandidate <- onRequestVote endpoint name $ \req -> do
        debugM _log $ printf "Server %v received vote request from %v" name (show $ rvCandidate req)
        (raft,vote,reason) <- atomically $ do
            raft <- readTVar (raftContext vRaft)
            let log = raftLog raft
            if (rvCandidateTerm req) < (raftCurrentTerm raft)
                then return (raft,False,"Candidate term too old")
                else do
                    modifyTVar (raftContext vRaft) $ \oldRaft -> setRaftTerm (rvCandidateTerm req) oldRaft
                    case raftStateLastCandidate $ raftState raft of
                        Just candidate -> do
                            if (candidate == rvCandidate req)
                                then return (raft,True,"Candidate already seen")
                                else return (raft,False,"Already saw different candidate")
                        Nothing -> do
                            modifyTVar (raftContext vRaft) $ \oldRaft ->
                                    setRaftLastCandidate (Just $ rvCandidate req) oldRaft
                            if name == rvCandidate req
                                then return (raft,True,"Voting for self")
                                else do
                                    if (rvCandidateLastEntryTime req) >= (lastAppendedTime log)
                                        then do
                                            modifyTVar (raftContext vRaft) $ \oldRaft -> 
                                                setRaftLastCandidate (Just $ rvCandidate req) oldRaft
                                            return (raft,True,"Candidate log more up to date")
                                        else return (raft,False,"Candidate log out of date")
        infoM _log $ printf "Server %v vote for %v is %v because %v" name (rvCandidate req) (show (raftCurrentTerm raft,vote)) reason
        return $ mkResult vote raft
    if leading && votedForCandidate
        then return ()
        else doVote vRaft

{-|
Initiate an election, volunteering to lead the cluster if elected.
-}