github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/p2p/datasets.go (about)

     1  package p2p
     2  
     3  // TODO (ramfox): relies on old `depQriProtocolID`
     4  // Should have its own protocol & protobuf & not rely on the Message struct
     5  
     6  import (
     7  	"context"
     8  	"encoding/json"
     9  	"fmt"
    10  
    11  	peer "github.com/libp2p/go-libp2p-core/peer"
    12  	"github.com/qri-io/qri/base"
    13  	p2putil "github.com/qri-io/qri/p2p/p2putil"
    14  	reporef "github.com/qri-io/qri/repo/ref"
    15  )
    16  
    17  // MtDatasets is a dataset list message
    18  const MtDatasets = p2putil.MsgType("list_datasets")
    19  
    20  // listMax is the highest number of entries a list request should return
    21  const listMax = 30
    22  
    23  // DatasetsListParams encapsulates options for requesting datasets
    24  type DatasetsListParams struct {
    25  	Term   string
    26  	Limit  int
    27  	Offset int
    28  }
    29  
    30  // RequestDatasetsList gets a list of a peer's datasets
    31  func (n *QriNode) RequestDatasetsList(ctx context.Context, pid peer.ID, p DatasetsListParams) ([]reporef.DatasetRef, error) {
    32  	log.Debugf("%s RequestDatasetList: %s", n.ID, pid)
    33  
    34  	if pid == n.ID {
    35  		// requesting self isn't a network operation
    36  		return n.Repo.References(p.Offset, p.Limit)
    37  	}
    38  
    39  	if !n.Online {
    40  		return nil, fmt.Errorf("not connected to p2p network")
    41  	}
    42  
    43  	req, err := p2putil.NewJSONBodyMessage(n.ID, MtDatasets, p)
    44  	if err != nil {
    45  		log.Debug(err.Error())
    46  		return nil, err
    47  	}
    48  
    49  	req = req.WithHeaders("phase", "request")
    50  
    51  	s, err := n.host.NewStream(ctx, pid, depQriProtocolID)
    52  	if err != nil {
    53  		return nil, fmt.Errorf("error opening stream: %s", err.Error())
    54  	}
    55  	defer s.Close()
    56  
    57  	ws := p2putil.WrapStream(s)
    58  	if err := ws.SendMessage(req); err != nil {
    59  		return nil, err
    60  	}
    61  
    62  	res, err := ws.ReceiveMessage()
    63  	if err != nil {
    64  		return nil, err
    65  	}
    66  
    67  	ref := []reporef.DatasetRef{}
    68  	err = json.Unmarshal(res.Body, &ref)
    69  	return ref, err
    70  }
    71  
    72  func (n *QriNode) handleDatasetsList(ws *p2putil.WrappedStream, msg p2putil.Message) (hangup bool) {
    73  	hangup = true
    74  	switch msg.Header("phase") {
    75  	case "request":
    76  		dlp := DatasetsListParams{}
    77  		if err := json.Unmarshal(msg.Body, &dlp); err != nil {
    78  			log.Debugf("%s %s", n.ID, err.Error())
    79  			return
    80  		}
    81  
    82  		if dlp.Limit == 0 || dlp.Limit > listMax {
    83  			dlp.Limit = listMax
    84  		}
    85  
    86  		refs, err := base.ListDatasets(context.TODO(), n.Repo, dlp.Term, "", dlp.Offset, dlp.Limit, true, false)
    87  		if err != nil {
    88  			log.Error(err)
    89  			return
    90  		}
    91  
    92  		reply, err := msg.UpdateJSON(refs)
    93  		reply = reply.WithHeaders("phase", "response")
    94  		if err := ws.SendMessage(reply); err != nil {
    95  			log.Debug(err.Error())
    96  			return
    97  		}
    98  	}
    99  
   100  	return
   101  }