github.com/holochain/holochain-proto@v0.1.0-alpha-26.0.20200915073418-5c83169c9b5b/bs.go (about)

     1  // Copyright (C) 2013-2018, The MetaCurrency Project (Eric Harris-Braun, Arthur Brock, et. al.)
     2  // Use of this source code is governed by GPLv3 found in the LICENSE file
     3  //----------------------------------------------------------------------------------------
     4  
     5  // implements bootstrap server access
     6  
     7  package holochain
     8  
     9  import (
    10  	"bytes"
    11  	"encoding/json"
    12  	"errors"
    13  	"fmt"
    14  	peer "github.com/libp2p/go-libp2p-peer"
    15  	pstore "github.com/libp2p/go-libp2p-peerstore"
    16  	ma "github.com/multiformats/go-multiaddr"
    17  	"io/ioutil"
    18  	"net/http"
    19  	"strings"
    20  	"time"
    21  )
    22  
    23  const (
    24  	BootstrapTTL = time.Minute * 5
    25  )
    26  
    27  type BSReq struct {
    28  	Version  int
    29  	NodeID   string
    30  	NodeAddr string
    31  }
    32  
    33  type BSResp struct {
    34  	Req      BSReq
    35  	Remote   string
    36  	LastSeen time.Time
    37  }
    38  
    39  func (h *Holochain) BSpost() (err error) {
    40  	if h.node == nil {
    41  		return errors.New("Node hasn't been initialized yet.")
    42  	}
    43  	nodeID := h.nodeIDStr
    44  	req := BSReq{Version: 1, NodeID: nodeID, NodeAddr: h.node.ExternalAddr().String()}
    45  	host := h.Config.BootstrapServer
    46  	id := h.DNAHash()
    47  	url := fmt.Sprintf("http://%s/%s/%s", host, id.String(), nodeID)
    48  	var b []byte
    49  	b, err = json.Marshal(req)
    50  	//var resp *http.Response
    51  	if err == nil {
    52  		var resp *http.Response
    53  		resp, err = http.Post(url, "application/json", bytes.NewBuffer(b))
    54  		if err == nil {
    55  			resp.Body.Close()
    56  		}
    57  
    58  	}
    59  	return
    60  }
    61  
    62  func (h *Holochain) checkBSResponses(nodes []BSResp) (err error) {
    63  	myNodeID := h.nodeIDStr
    64  	for _, r := range nodes {
    65  		h.dht.dlog.Logf("checking returned node: %v", r)
    66  
    67  		var id peer.ID
    68  		var addr ma.Multiaddr
    69  		id, err = peer.IDB58Decode(r.Req.NodeID)
    70  		if err == nil {
    71  			//@TODO figure when to use Remote or r.NodeAddr
    72  			x := strings.Split(r.Remote, ":")
    73  			y := strings.Split(r.Req.NodeAddr, "/")
    74  			port := y[len(y)-1]
    75  
    76  			// assume the multi-address is the ip address as the bootstrap server saw it
    77  			// with port number advertised by the node in it's multi-address
    78  
    79  			addr, err = ma.NewMultiaddr("/ip4/" + x[0] + "/tcp/" + port)
    80  			if err == nil {
    81  				// don't "discover" ourselves
    82  				if r.Req.NodeID != myNodeID {
    83  					h.dht.dlog.Logf("discovered peer via bs: %s (%v)", r.Req.NodeID, addr)
    84  					go func() {
    85  						err = h.AddPeer(pstore.PeerInfo{ID: id, Addrs: []ma.Multiaddr{addr}})
    86  					}()
    87  				}
    88  
    89  			}
    90  		}
    91  	}
    92  	return
    93  }
    94  
    95  func (h *Holochain) BSget() (err error) {
    96  	if h.node == nil {
    97  		return errors.New("Node hasn't been initialized yet.")
    98  	}
    99  	host := h.Config.BootstrapServer
   100  	if host == "" {
   101  		return
   102  	}
   103  	id := h.DNAHash()
   104  	url := fmt.Sprintf("http://%s/%s", host, id.String())
   105  
   106  	var req *http.Request
   107  
   108  	req, err = http.NewRequest("GET", url, nil)
   109  	if err != nil {
   110  		return
   111  	}
   112  	req.Close = true
   113  	client := http.DefaultClient
   114  	var resp *http.Response
   115  	resp, err = client.Do(req)
   116  
   117  	//	resp, err = http.Get(url)
   118  	if err == nil {
   119  		var b []byte
   120  		b, err = ioutil.ReadAll(resp.Body)
   121  		if err == nil {
   122  			var nodes []BSResp
   123  			err = json.Unmarshal(b, &nodes)
   124  			if err == nil {
   125  				err = h.checkBSResponses(nodes)
   126  
   127  			}
   128  		}
   129  		resp.Body.Close()
   130  
   131  	}
   132  	return
   133  }