github.com/alpe/etcd@v0.1.2-0.20130915230056-09f31af88aeb/transporter.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/tls"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io"
     9  	"net"
    10  	"net/http"
    11  	"time"
    12  
    13  	"github.com/coreos/go-raft"
    14  )
    15  
    16  // Transporter layer for communication between raft nodes
    17  type transporter struct {
    18  	client  *http.Client
    19  	timeout time.Duration
    20  }
    21  
    22  // response struct
    23  type transporterResponse struct {
    24  	resp *http.Response
    25  	err  error
    26  }
    27  
    28  // Create transporter using by raft server
    29  // Create http or https transporter based on
    30  // whether the user give the server cert and key
    31  func newTransporter(scheme string, tlsConf tls.Config, timeout time.Duration) *transporter {
    32  	t := transporter{}
    33  
    34  	tr := &http.Transport{
    35  		Dial: dialTimeout,
    36  	}
    37  
    38  	if scheme == "https" {
    39  		tr.TLSClientConfig = &tlsConf
    40  		tr.DisableCompression = true
    41  	}
    42  
    43  	t.client = &http.Client{Transport: tr}
    44  	t.timeout = timeout
    45  
    46  	return &t
    47  }
    48  
    49  // Dial with timeout
    50  func dialTimeout(network, addr string) (net.Conn, error) {
    51  	return net.DialTimeout(network, addr, HTTPTimeout)
    52  }
    53  
    54  // Sends AppendEntries RPCs to a peer when the server is the leader.
    55  func (t *transporter) SendAppendEntriesRequest(server *raft.Server, peer *raft.Peer, req *raft.AppendEntriesRequest) *raft.AppendEntriesResponse {
    56  	var aersp *raft.AppendEntriesResponse
    57  	var b bytes.Buffer
    58  
    59  	json.NewEncoder(&b).Encode(req)
    60  
    61  	size := b.Len()
    62  
    63  	r.serverStats.SendAppendReq(size)
    64  
    65  	u, _ := nameToRaftURL(peer.Name)
    66  
    67  	debugf("Send LogEntries to %s ", u)
    68  
    69  	thisPeerStats, ok := r.peersStats[peer.Name]
    70  
    71  	start := time.Now()
    72  
    73  	resp, err := t.Post(fmt.Sprintf("%s/log/append", u), &b)
    74  
    75  	end := time.Now()
    76  
    77  	if err != nil {
    78  		debugf("Cannot send AppendEntriesRequest to %s: %s", u, err)
    79  		if ok {
    80  			thisPeerStats.Fail()
    81  		}
    82  	} else {
    83  		if ok {
    84  			thisPeerStats.Succ(end.Sub(start))
    85  		}
    86  	}
    87  
    88  	r.peersStats[peer.Name] = thisPeerStats
    89  
    90  	if resp != nil {
    91  		defer resp.Body.Close()
    92  		aersp = &raft.AppendEntriesResponse{}
    93  		if err := json.NewDecoder(resp.Body).Decode(&aersp); err == nil || err == io.EOF {
    94  			return aersp
    95  		}
    96  
    97  	}
    98  
    99  	return aersp
   100  }
   101  
   102  // Sends RequestVote RPCs to a peer when the server is the candidate.
   103  func (t *transporter) SendVoteRequest(server *raft.Server, peer *raft.Peer, req *raft.RequestVoteRequest) *raft.RequestVoteResponse {
   104  	var rvrsp *raft.RequestVoteResponse
   105  	var b bytes.Buffer
   106  	json.NewEncoder(&b).Encode(req)
   107  
   108  	u, _ := nameToRaftURL(peer.Name)
   109  	debugf("Send Vote to %s", u)
   110  
   111  	resp, err := t.Post(fmt.Sprintf("%s/vote", u), &b)
   112  
   113  	if err != nil {
   114  		debugf("Cannot send VoteRequest to %s : %s", u, err)
   115  	}
   116  
   117  	if resp != nil {
   118  		defer resp.Body.Close()
   119  		rvrsp := &raft.RequestVoteResponse{}
   120  		if err := json.NewDecoder(resp.Body).Decode(&rvrsp); err == nil || err == io.EOF {
   121  			return rvrsp
   122  		}
   123  
   124  	}
   125  	return rvrsp
   126  }
   127  
   128  // Sends SnapshotRequest RPCs to a peer when the server is the candidate.
   129  func (t *transporter) SendSnapshotRequest(server *raft.Server, peer *raft.Peer, req *raft.SnapshotRequest) *raft.SnapshotResponse {
   130  	var aersp *raft.SnapshotResponse
   131  	var b bytes.Buffer
   132  	json.NewEncoder(&b).Encode(req)
   133  
   134  	u, _ := nameToRaftURL(peer.Name)
   135  	debugf("Send Snapshot to %s [Last Term: %d, LastIndex %d]", u,
   136  		req.LastTerm, req.LastIndex)
   137  
   138  	resp, err := t.Post(fmt.Sprintf("%s/snapshot", u), &b)
   139  
   140  	if err != nil {
   141  		debugf("Cannot send SendSnapshotRequest to %s : %s", u, err)
   142  	}
   143  
   144  	if resp != nil {
   145  		defer resp.Body.Close()
   146  		aersp = &raft.SnapshotResponse{}
   147  		if err = json.NewDecoder(resp.Body).Decode(&aersp); err == nil || err == io.EOF {
   148  
   149  			return aersp
   150  		}
   151  	}
   152  
   153  	return aersp
   154  }
   155  
   156  // Sends SnapshotRecoveryRequest RPCs to a peer when the server is the candidate.
   157  func (t *transporter) SendSnapshotRecoveryRequest(server *raft.Server, peer *raft.Peer, req *raft.SnapshotRecoveryRequest) *raft.SnapshotRecoveryResponse {
   158  	var aersp *raft.SnapshotRecoveryResponse
   159  	var b bytes.Buffer
   160  	json.NewEncoder(&b).Encode(req)
   161  
   162  	u, _ := nameToRaftURL(peer.Name)
   163  	debugf("Send SnapshotRecovery to %s [Last Term: %d, LastIndex %d]", u,
   164  		req.LastTerm, req.LastIndex)
   165  
   166  	resp, err := t.Post(fmt.Sprintf("%s/snapshotRecovery", u), &b)
   167  
   168  	if err != nil {
   169  		debugf("Cannot send SendSnapshotRecoveryRequest to %s : %s", u, err)
   170  	}
   171  
   172  	if resp != nil {
   173  		defer resp.Body.Close()
   174  		aersp = &raft.SnapshotRecoveryResponse{}
   175  		if err = json.NewDecoder(resp.Body).Decode(&aersp); err == nil || err == io.EOF {
   176  			return aersp
   177  		}
   178  	}
   179  
   180  	return aersp
   181  }
   182  
   183  // Send server side POST request
   184  func (t *transporter) Post(path string, body io.Reader) (*http.Response, error) {
   185  
   186  	c := make(chan *transporterResponse, 1)
   187  
   188  	go func() {
   189  		tr := new(transporterResponse)
   190  		tr.resp, tr.err = t.client.Post(path, "application/json", body)
   191  		c <- tr
   192  	}()
   193  
   194  	return t.waitResponse(c)
   195  
   196  }
   197  
   198  // Send server side GET request
   199  func (t *transporter) Get(path string) (*http.Response, error) {
   200  
   201  	c := make(chan *transporterResponse, 1)
   202  
   203  	go func() {
   204  		tr := new(transporterResponse)
   205  		tr.resp, tr.err = t.client.Get(path)
   206  		c <- tr
   207  	}()
   208  
   209  	return t.waitResponse(c)
   210  }
   211  
   212  func (t *transporter) waitResponse(responseChan chan *transporterResponse) (*http.Response, error) {
   213  
   214  	timeoutChan := time.After(t.timeout)
   215  
   216  	select {
   217  	case <-timeoutChan:
   218  		return nil, fmt.Errorf("Wait Response Timeout: %v", t.timeout)
   219  
   220  	case r := <-responseChan:
   221  		return r.resp, r.err
   222  	}
   223  
   224  	// for complier
   225  	return nil, nil
   226  }