func (d *Dinghy) RequestVoteHandler() func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.Body != nil {
			defer r.Body.Close()
		}
		if r.Method != "POST" {
			d.logger.Errorf("invalid method %s", r.Method)
			http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
			return
		}

		var rv requestVoteRequest
		if err := json.NewDecoder(r.Body).Decode(&rv); err != nil {
			d.logger.Errorf("%s", err)
			http.Error(w, emptyRequestVoteResponse.String(), http.StatusBadRequest)
			return
		}

		switch {
		case rv.Term < d.State.Term():
			// The request is from an old term so reject
			d.logger.Printf("got RequestVote request from older term, rejecting %+v %s", rv, d.State)
			rvResp := requestVoteResponse{
				Term:        d.State.Term(),
				VoteGranted: false,
				Reason:      fmt.Sprintf("term %d < %d", rv.Term, d.State.Term()),
			}
			if d.State.State() == StateLeader {
				rvResp.Reason = "already leader"
			}
			if err := json.NewEncoder(w).Encode(rvResp); err != nil {
				http.Error(w, emptyRequestVoteResponse.String(), http.StatusInternalServerError)
			}
			return
		case (d.State.VotedFor() != NoVote) && (d.State.VotedFor() != rv.CandidateID):
			// don't double vote if already voted for a term
			d.logger.Printf("got RequestVote request but already voted, rejecting %+v %s", rv, d.State)
			rvResp := requestVoteResponse{
				Term:        d.State.Term(),
				VoteGranted: false,
				Reason:      fmt.Sprintf("already cast vote for %d", d.State.VotedFor()),
			}
			if err := json.NewEncoder(w).Encode(rvResp); err != nil {
				http.Error(w, emptyRequestVoteResponse.String(), http.StatusInternalServerError)
			}
			return
		case rv.Term > d.State.Term():
			// Step down and reset state on newer term.
			d.logger.Printf("got RequestVote request from newer term, stepping down %+v %s", rv, d.State)
			d.State.StepDown(rv.Term)
			d.State.LeaderID(UnknownLeaderID)
		}

		// ok and vote for candidate
		// reset election timeout
		d.logger.Printf("got RequestVote request, voting for candidate id %d %s", rv.CandidateID, d.State)
		d.State.VotedFor(rv.CandidateID)
		//defer d.State.HeartbeatReset(true)
		rvResp := requestVoteResponse{
			Term:        d.State.Term(),
			VoteGranted: true,
		}
		if err := json.NewEncoder(w).Encode(rvResp); err != nil {
			http.Error(w, emptyRequestVoteResponse.String(), http.StatusInternalServerError)
		}
		return
	}
}
// RequestVoteHandler (POST) handles requests for votes
RequestVoteHandler (POST) handles requests for votes
// RequestVoteHandler ( POST ) handles requests for votes
func (d *Dinghy) RequestVoteHandler() func(w http.ResponseWriter, r *http.Request) {
	return func(w http.ResponseWriter, r *http.Request) {
		if r.Body != nil {
			defer r.Body.Close()
		}
		if r.Method != "POST" {
			d.logger.Errorf("invalid method %s", r.Method)
			http.Error(w, http.StatusText(http.StatusMethodNotAllowed), http.StatusMethodNotAllowed)
			return
		}
		var rv requestVoteRequest
		if err := json.NewDecoder(r.Body).Decode(&rv); err != nil {
			d.logger.Errorf("%s", err)
			http.Error(w, emptyRequestVoteResponse.String(), http.StatusBadRequest)
			return
		}
		switch {
		case rv.Term < d.State.Term():
			d.logger.Printf("got RequestVote request from older term, rejecting %+v %s", rv, d.State)
			rvResp := requestVoteResponse{
				Term:        d.State.Term(),
				VoteGranted: false,
				Reason:      fmt.Sprintf("term %d < %d", rv.Term, d.State.Term()),
			}
			if d.State.State() == StateLeader {
				rvResp.Reason = "already leader"
			}
			if err := json.NewEncoder(w).Encode(rvResp); err != nil {
				http.Error(w, emptyRequestVoteResponse.String(), http.StatusInternalServerError)
			}
			return
		case (d.State.VotedFor() != NoVote) && (d.State.VotedFor() != rv.CandidateID):
			d.logger.Printf("got RequestVote request but already voted, rejecting %+v %s", rv, d.State)
			rvResp := requestVoteResponse{
				Term:        d.State.Term(),
				VoteGranted: false,
				Reason:      fmt.Sprintf("already cast vote for %d", d.State.VotedFor()),
			}
			if err := json.NewEncoder(w).Encode(rvResp); err != nil {
				http.Error(w, emptyRequestVoteResponse.String(), http.StatusInternalServerError)
			}
			return
		case rv.Term > d.State.Term():
			d.logger.Printf("got RequestVote request from newer term, stepping down %+v %s", rv, d.State)
			d.State.StepDown(rv.Term)
			d.State.LeaderID(UnknownLeaderID)
		}
		d.logger.Printf("got RequestVote request, voting for candidate id %d %s", rv.CandidateID, d.State)
		d.State.VotedFor(rv.CandidateID)
		rvResp := requestVoteResponse{
			Term:        d.State.Term(),
			VoteGranted: true,
		}
		if err := json.NewEncoder(w).Encode(rvResp); err != nil {
			http.Error(w, emptyRequestVoteResponse.String(), http.StatusInternalServerError)
		}
		return
	}
}
func ( d * Dinghy ) RequestVoteHandler ( ) func ( w http . ResponseWriter , r * http . Request ) { return func ( w http . ResponseWriter , r * http . Request ) { if r . Body != nil { defer r . Body . Close ( ) } if r . Method != " " { d . logger . Errorf ( " " , r . Method ) http . Error ( w , http . StatusText ( http . StatusMethodNotAllowed ) , http . StatusMethodNotAllowed ) return } var rv requestVoteRequest if err := json . NewDecoder ( r . Body ) . Decode ( & rv ) ; err != nil { d . logger . Errorf ( " " , err ) http . Error ( w , emptyRequestVoteResponse . String ( ) , http . StatusBadRequest ) return } switch { case rv . Term < d . State . Term ( ) : d . logger . Printf ( " " , rv , d . State ) rvResp := requestVoteResponse { Term : d . State . Term ( ) , VoteGranted : false , Reason : fmt . Sprintf ( " " , rv . Term , d . State . Term ( ) ) , } if d . State . State ( ) == StateLeader { rvResp . Reason = " " } if err := json . NewEncoder ( w ) . Encode ( rvResp ) ; err != nil { http . Error ( w , emptyRequestVoteResponse . String ( ) , http . StatusInternalServerError ) } return case ( d . State . VotedFor ( ) != NoVote ) && ( d . State . VotedFor ( ) != rv . CandidateID ) : d . logger . Printf ( " " , rv , d . State ) rvResp := requestVoteResponse { Term : d . State . Term ( ) , VoteGranted : false , Reason : fmt . Sprintf ( " " , d . State . VotedFor ( ) ) , } if err := json . NewEncoder ( w ) . Encode ( rvResp ) ; err != nil { http . Error ( w , emptyRequestVoteResponse . String ( ) , http . StatusInternalServerError ) } return case rv . Term > d . State . Term ( ) : d . logger . Printf ( " " , rv , d . State ) d . State . StepDown ( rv . Term ) d . State . LeaderID ( UnknownLeaderID ) } d . logger . Printf ( " " , rv . CandidateID , d . State ) d . State . VotedFor ( rv . CandidateID ) rvResp := requestVoteResponse { Term : d . State . Term ( ) , VoteGranted : true , } if err := json . NewEncoder ( w ) . Encode ( rvResp ) ; err != nil { http . Error ( w , emptyRequestVoteResponse . String ( ) , http . StatusInternalServerError ) } return } }
RequestVoteHandler (POST) handles requests for votes
RequestVoteHandler ( POST ) handles requests for votes
// The request is from an old term so reject // don't double vote if already voted for a term // Step down and reset state on newer term. // ok and vote for candidate // reset election timeout //defer d.State.HeartbeatReset(true)