github.com/keltia/go-ipfs@v0.3.8-0.20150909044612-210793031c63/core/commands/dht.go (about)

     1  package commands
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  	"time"
     9  
    10  	key "github.com/ipfs/go-ipfs/blocks/key"
    11  	cmds "github.com/ipfs/go-ipfs/commands"
    12  	notif "github.com/ipfs/go-ipfs/notifications"
    13  	peer "github.com/ipfs/go-ipfs/p2p/peer"
    14  	ipdht "github.com/ipfs/go-ipfs/routing/dht"
    15  	u "github.com/ipfs/go-ipfs/util"
    16  )
    17  
    18  var ErrNotDHT = errors.New("routing service is not a DHT")
    19  
    20  var DhtCmd = &cmds.Command{
    21  	Helptext: cmds.HelpText{
    22  		Tagline:          "Issue commands directly through the DHT",
    23  		ShortDescription: ``,
    24  	},
    25  
    26  	Subcommands: map[string]*cmds.Command{
    27  		"query":     queryDhtCmd,
    28  		"findprovs": findProvidersDhtCmd,
    29  		"findpeer":  findPeerDhtCmd,
    30  		"get":       getValueDhtCmd,
    31  		"put":       putValueDhtCmd,
    32  	},
    33  }
    34  
    35  var queryDhtCmd = &cmds.Command{
    36  	Helptext: cmds.HelpText{
    37  		Tagline:          "Run a 'findClosestPeers' query through the DHT",
    38  		ShortDescription: ``,
    39  	},
    40  
    41  	Arguments: []cmds.Argument{
    42  		cmds.StringArg("peerID", true, true, "The peerID to run the query against"),
    43  	},
    44  	Options: []cmds.Option{
    45  		cmds.BoolOption("verbose", "v", "Write extra information"),
    46  	},
    47  	Run: func(req cmds.Request, res cmds.Response) {
    48  		n, err := req.InvocContext().GetNode()
    49  		if err != nil {
    50  			res.SetError(err, cmds.ErrNormal)
    51  			return
    52  		}
    53  
    54  		dht, ok := n.Routing.(*ipdht.IpfsDHT)
    55  		if !ok {
    56  			res.SetError(ErrNotDHT, cmds.ErrNormal)
    57  			return
    58  		}
    59  
    60  		events := make(chan *notif.QueryEvent)
    61  		ctx := notif.RegisterForQueryEvents(req.Context(), events)
    62  
    63  		closestPeers, err := dht.GetClosestPeers(ctx, key.Key(req.Arguments()[0]))
    64  		if err != nil {
    65  			res.SetError(err, cmds.ErrNormal)
    66  			return
    67  		}
    68  
    69  		go func() {
    70  			defer close(events)
    71  			for p := range closestPeers {
    72  				notif.PublishQueryEvent(ctx, &notif.QueryEvent{
    73  					ID:   p,
    74  					Type: notif.FinalPeer,
    75  				})
    76  			}
    77  		}()
    78  
    79  		outChan := make(chan interface{})
    80  		res.SetOutput((<-chan interface{})(outChan))
    81  
    82  		go func() {
    83  			defer close(outChan)
    84  			for e := range events {
    85  				outChan <- e
    86  			}
    87  		}()
    88  	},
    89  	Marshalers: cmds.MarshalerMap{
    90  		cmds.Text: func(res cmds.Response) (io.Reader, error) {
    91  			outChan, ok := res.Output().(<-chan interface{})
    92  			if !ok {
    93  				return nil, u.ErrCast()
    94  			}
    95  
    96  			marshal := func(v interface{}) (io.Reader, error) {
    97  				obj, ok := v.(*notif.QueryEvent)
    98  				if !ok {
    99  					return nil, u.ErrCast()
   100  				}
   101  
   102  				verbose, _, _ := res.Request().Option("v").Bool()
   103  
   104  				buf := new(bytes.Buffer)
   105  				if verbose {
   106  					fmt.Fprintf(buf, "%s: ", time.Now().Format("15:04:05.000"))
   107  				}
   108  				switch obj.Type {
   109  				case notif.FinalPeer:
   110  					fmt.Fprintf(buf, "%s\n", obj.ID)
   111  				case notif.PeerResponse:
   112  					if verbose {
   113  						fmt.Fprintf(buf, "* %s says use ", obj.ID)
   114  						for _, p := range obj.Responses {
   115  							fmt.Fprintf(buf, "%s ", p.ID)
   116  						}
   117  						fmt.Fprintln(buf)
   118  					}
   119  				case notif.SendingQuery:
   120  					if verbose {
   121  						fmt.Fprintf(buf, "* querying %s\n", obj.ID)
   122  					}
   123  				case notif.QueryError:
   124  					fmt.Fprintf(buf, "error: %s\n", obj.Extra)
   125  				default:
   126  					fmt.Fprintf(buf, "unrecognized event type: %d\n", obj.Type)
   127  				}
   128  				return buf, nil
   129  			}
   130  
   131  			return &cmds.ChannelMarshaler{
   132  				Channel:   outChan,
   133  				Marshaler: marshal,
   134  				Res:       res,
   135  			}, nil
   136  		},
   137  	},
   138  	Type: notif.QueryEvent{},
   139  }
   140  
   141  var findProvidersDhtCmd = &cmds.Command{
   142  	Helptext: cmds.HelpText{
   143  		Tagline: "Run a 'FindProviders' query through the DHT",
   144  		ShortDescription: `
   145  FindProviders will return a list of peers who are able to provide the value requested.
   146  `,
   147  	},
   148  
   149  	Arguments: []cmds.Argument{
   150  		cmds.StringArg("key", true, true, "The key to find providers for"),
   151  	},
   152  	Options: []cmds.Option{
   153  		cmds.BoolOption("verbose", "v", "Write extra information"),
   154  	},
   155  	Run: func(req cmds.Request, res cmds.Response) {
   156  		n, err := req.InvocContext().GetNode()
   157  		if err != nil {
   158  			res.SetError(err, cmds.ErrNormal)
   159  			return
   160  		}
   161  
   162  		dht, ok := n.Routing.(*ipdht.IpfsDHT)
   163  		if !ok {
   164  			res.SetError(ErrNotDHT, cmds.ErrNormal)
   165  			return
   166  		}
   167  
   168  		numProviders := 20
   169  
   170  		outChan := make(chan interface{})
   171  		res.SetOutput((<-chan interface{})(outChan))
   172  
   173  		events := make(chan *notif.QueryEvent)
   174  		ctx := notif.RegisterForQueryEvents(req.Context(), events)
   175  
   176  		pchan := dht.FindProvidersAsync(ctx, key.B58KeyDecode(req.Arguments()[0]), numProviders)
   177  		go func() {
   178  			defer close(outChan)
   179  			for e := range events {
   180  				outChan <- e
   181  			}
   182  		}()
   183  
   184  		go func() {
   185  			defer close(events)
   186  			for p := range pchan {
   187  				np := p
   188  				notif.PublishQueryEvent(ctx, &notif.QueryEvent{
   189  					Type:      notif.Provider,
   190  					Responses: []*peer.PeerInfo{&np},
   191  				})
   192  			}
   193  		}()
   194  	},
   195  	Marshalers: cmds.MarshalerMap{
   196  		cmds.Text: func(res cmds.Response) (io.Reader, error) {
   197  			outChan, ok := res.Output().(<-chan interface{})
   198  			if !ok {
   199  				return nil, u.ErrCast()
   200  			}
   201  
   202  			verbose, _, _ := res.Request().Option("v").Bool()
   203  
   204  			marshal := func(v interface{}) (io.Reader, error) {
   205  				obj, ok := v.(*notif.QueryEvent)
   206  				if !ok {
   207  					return nil, u.ErrCast()
   208  				}
   209  
   210  				buf := new(bytes.Buffer)
   211  				if verbose {
   212  					fmt.Fprintf(buf, "%s: ", time.Now().Format("15:04:05.000"))
   213  				}
   214  				switch obj.Type {
   215  				case notif.FinalPeer:
   216  					if verbose {
   217  						fmt.Fprintf(buf, "* closest peer %s\n", obj.ID)
   218  					}
   219  				case notif.Provider:
   220  					prov := obj.Responses[0]
   221  					if verbose {
   222  						fmt.Fprintf(buf, "provider: ")
   223  					}
   224  					fmt.Fprintf(buf, "%s\n", prov.ID.Pretty())
   225  					if verbose {
   226  						for _, a := range prov.Addrs {
   227  							fmt.Fprintf(buf, "\t%s\n", a)
   228  						}
   229  					}
   230  				case notif.PeerResponse:
   231  					if verbose {
   232  						fmt.Fprintf(buf, "* %s says use ", obj.ID)
   233  						for _, p := range obj.Responses {
   234  							fmt.Fprintf(buf, "%s ", p.ID)
   235  						}
   236  						fmt.Fprintln(buf)
   237  					}
   238  				case notif.SendingQuery:
   239  					if verbose {
   240  						fmt.Fprintf(buf, "* querying %s\n", obj.ID)
   241  					}
   242  				case notif.QueryError:
   243  					fmt.Fprintf(buf, "error: %s\n", obj.Extra)
   244  				default:
   245  					fmt.Fprintf(buf, "unrecognized event type: %d\n", obj.Type)
   246  				}
   247  				return buf, nil
   248  			}
   249  
   250  			return &cmds.ChannelMarshaler{
   251  				Channel:   outChan,
   252  				Marshaler: marshal,
   253  				Res:       res,
   254  			}, nil
   255  		},
   256  	},
   257  	Type: notif.QueryEvent{},
   258  }
   259  
   260  var findPeerDhtCmd = &cmds.Command{
   261  	Helptext: cmds.HelpText{
   262  		Tagline:          "Run a 'FindPeer' query through the DHT",
   263  		ShortDescription: ``,
   264  	},
   265  
   266  	Arguments: []cmds.Argument{
   267  		cmds.StringArg("peerID", true, true, "The peer to search for"),
   268  	},
   269  	Run: func(req cmds.Request, res cmds.Response) {
   270  		n, err := req.InvocContext().GetNode()
   271  		if err != nil {
   272  			res.SetError(err, cmds.ErrNormal)
   273  			return
   274  		}
   275  
   276  		dht, ok := n.Routing.(*ipdht.IpfsDHT)
   277  		if !ok {
   278  			res.SetError(ErrNotDHT, cmds.ErrNormal)
   279  			return
   280  		}
   281  
   282  		pid, err := peer.IDB58Decode(req.Arguments()[0])
   283  		if err != nil {
   284  			res.SetError(err, cmds.ErrNormal)
   285  			return
   286  		}
   287  
   288  		outChan := make(chan interface{})
   289  		res.SetOutput((<-chan interface{})(outChan))
   290  
   291  		events := make(chan *notif.QueryEvent)
   292  		ctx := notif.RegisterForQueryEvents(req.Context(), events)
   293  
   294  		go func() {
   295  			defer close(outChan)
   296  			for v := range events {
   297  				outChan <- v
   298  			}
   299  		}()
   300  
   301  		go func() {
   302  			defer close(events)
   303  			pi, err := dht.FindPeer(ctx, pid)
   304  			if err != nil {
   305  				notif.PublishQueryEvent(ctx, &notif.QueryEvent{
   306  					Type:  notif.QueryError,
   307  					Extra: err.Error(),
   308  				})
   309  				return
   310  			}
   311  
   312  			notif.PublishQueryEvent(ctx, &notif.QueryEvent{
   313  				Type:      notif.FinalPeer,
   314  				Responses: []*peer.PeerInfo{&pi},
   315  			})
   316  		}()
   317  	},
   318  	Marshalers: cmds.MarshalerMap{
   319  		cmds.Text: func(res cmds.Response) (io.Reader, error) {
   320  			outChan, ok := res.Output().(<-chan interface{})
   321  			if !ok {
   322  				return nil, u.ErrCast()
   323  			}
   324  
   325  			marshal := func(v interface{}) (io.Reader, error) {
   326  				obj, ok := v.(*notif.QueryEvent)
   327  				if !ok {
   328  					return nil, u.ErrCast()
   329  				}
   330  
   331  				buf := new(bytes.Buffer)
   332  				fmt.Fprintf(buf, "%s: ", time.Now().Format("15:04:05.000"))
   333  				switch obj.Type {
   334  				case notif.FinalPeer:
   335  					pi := obj.Responses[0]
   336  					fmt.Fprintf(buf, "%s\n", pi.ID)
   337  					for _, a := range pi.Addrs {
   338  						fmt.Fprintf(buf, "\t%s\n", a)
   339  					}
   340  				case notif.PeerResponse:
   341  					fmt.Fprintf(buf, "* %s says use ", obj.ID)
   342  					for _, p := range obj.Responses {
   343  						fmt.Fprintf(buf, "%s ", p.ID)
   344  					}
   345  					fmt.Fprintln(buf)
   346  				case notif.SendingQuery:
   347  					fmt.Fprintf(buf, "* querying %s\n", obj.ID)
   348  				case notif.QueryError:
   349  					fmt.Fprintf(buf, "error: %s\n", obj.Extra)
   350  				default:
   351  					fmt.Fprintf(buf, "unrecognized event type: %d\n", obj.Type)
   352  				}
   353  				return buf, nil
   354  			}
   355  
   356  			return &cmds.ChannelMarshaler{
   357  				Channel:   outChan,
   358  				Marshaler: marshal,
   359  				Res:       res,
   360  			}, nil
   361  		},
   362  	},
   363  	Type: notif.QueryEvent{},
   364  }
   365  
   366  var getValueDhtCmd = &cmds.Command{
   367  	Helptext: cmds.HelpText{
   368  		Tagline: "Run a 'GetValue' query through the DHT",
   369  		ShortDescription: `
   370  GetValue will return the value stored in the dht at the given key.
   371  `,
   372  	},
   373  
   374  	Arguments: []cmds.Argument{
   375  		cmds.StringArg("key", true, true, "The key to find a value for"),
   376  	},
   377  	Options: []cmds.Option{
   378  		cmds.BoolOption("verbose", "v", "Write extra information"),
   379  	},
   380  	Run: func(req cmds.Request, res cmds.Response) {
   381  		n, err := req.InvocContext().GetNode()
   382  		if err != nil {
   383  			res.SetError(err, cmds.ErrNormal)
   384  			return
   385  		}
   386  
   387  		dht, ok := n.Routing.(*ipdht.IpfsDHT)
   388  		if !ok {
   389  			res.SetError(ErrNotDHT, cmds.ErrNormal)
   390  			return
   391  		}
   392  
   393  		outChan := make(chan interface{})
   394  		res.SetOutput((<-chan interface{})(outChan))
   395  
   396  		events := make(chan *notif.QueryEvent)
   397  		ctx := notif.RegisterForQueryEvents(req.Context(), events)
   398  
   399  		go func() {
   400  			defer close(outChan)
   401  			for e := range events {
   402  				outChan <- e
   403  			}
   404  		}()
   405  
   406  		go func() {
   407  			defer close(events)
   408  			val, err := dht.GetValue(ctx, key.B58KeyDecode(req.Arguments()[0]))
   409  			if err != nil {
   410  				notif.PublishQueryEvent(ctx, &notif.QueryEvent{
   411  					Type:  notif.QueryError,
   412  					Extra: err.Error(),
   413  				})
   414  			} else {
   415  				notif.PublishQueryEvent(ctx, &notif.QueryEvent{
   416  					Type:  notif.Value,
   417  					Extra: string(val),
   418  				})
   419  			}
   420  		}()
   421  	},
   422  	Marshalers: cmds.MarshalerMap{
   423  		cmds.Text: func(res cmds.Response) (io.Reader, error) {
   424  			outChan, ok := res.Output().(<-chan interface{})
   425  			if !ok {
   426  				return nil, u.ErrCast()
   427  			}
   428  
   429  			verbose, _, _ := res.Request().Option("v").Bool()
   430  
   431  			marshal := func(v interface{}) (io.Reader, error) {
   432  				obj, ok := v.(*notif.QueryEvent)
   433  				if !ok {
   434  					return nil, u.ErrCast()
   435  				}
   436  
   437  				buf := new(bytes.Buffer)
   438  				if verbose {
   439  					fmt.Fprintf(buf, "%s: ", time.Now().Format("15:04:05.000"))
   440  				}
   441  				switch obj.Type {
   442  				case notif.PeerResponse:
   443  					if verbose {
   444  						fmt.Fprintf(buf, "* %s says use ", obj.ID)
   445  						for _, p := range obj.Responses {
   446  							fmt.Fprintf(buf, "%s ", p.ID)
   447  						}
   448  						fmt.Fprintln(buf)
   449  					}
   450  				case notif.SendingQuery:
   451  					if verbose {
   452  						fmt.Fprintf(buf, "* querying %s\n", obj.ID)
   453  					}
   454  				case notif.Value:
   455  					fmt.Fprintf(buf, "got value: '%s'\n", obj.Extra)
   456  				case notif.QueryError:
   457  					fmt.Fprintf(buf, "error: %s\n", obj.Extra)
   458  				default:
   459  					fmt.Fprintf(buf, "unrecognized event type: %d\n", obj.Type)
   460  				}
   461  				return buf, nil
   462  			}
   463  
   464  			return &cmds.ChannelMarshaler{
   465  				Channel:   outChan,
   466  				Marshaler: marshal,
   467  				Res:       res,
   468  			}, nil
   469  		},
   470  	},
   471  	Type: notif.QueryEvent{},
   472  }
   473  
   474  var putValueDhtCmd = &cmds.Command{
   475  	Helptext: cmds.HelpText{
   476  		Tagline: "Run a 'PutValue' query through the DHT",
   477  		ShortDescription: `
   478  PutValue will store the given key value pair in the dht.
   479  `,
   480  	},
   481  
   482  	Arguments: []cmds.Argument{
   483  		cmds.StringArg("key", true, false, "The key to store the value at"),
   484  		cmds.StringArg("value", true, false, "The value to store").EnableStdin(),
   485  	},
   486  	Options: []cmds.Option{
   487  		cmds.BoolOption("verbose", "v", "Write extra information"),
   488  	},
   489  	Run: func(req cmds.Request, res cmds.Response) {
   490  		n, err := req.InvocContext().GetNode()
   491  		if err != nil {
   492  			res.SetError(err, cmds.ErrNormal)
   493  			return
   494  		}
   495  
   496  		dht, ok := n.Routing.(*ipdht.IpfsDHT)
   497  		if !ok {
   498  			res.SetError(ErrNotDHT, cmds.ErrNormal)
   499  			return
   500  		}
   501  
   502  		outChan := make(chan interface{})
   503  		res.SetOutput((<-chan interface{})(outChan))
   504  
   505  		events := make(chan *notif.QueryEvent)
   506  		ctx := notif.RegisterForQueryEvents(req.Context(), events)
   507  
   508  		key := key.B58KeyDecode(req.Arguments()[0])
   509  		data := req.Arguments()[1]
   510  
   511  		go func() {
   512  			defer close(outChan)
   513  			for e := range events {
   514  				outChan <- e
   515  			}
   516  		}()
   517  
   518  		go func() {
   519  			defer close(events)
   520  			err := dht.PutValue(ctx, key, []byte(data))
   521  			if err != nil {
   522  				notif.PublishQueryEvent(ctx, &notif.QueryEvent{
   523  					Type:  notif.QueryError,
   524  					Extra: err.Error(),
   525  				})
   526  			}
   527  		}()
   528  	},
   529  	Marshalers: cmds.MarshalerMap{
   530  		cmds.Text: func(res cmds.Response) (io.Reader, error) {
   531  			outChan, ok := res.Output().(<-chan interface{})
   532  			if !ok {
   533  				return nil, u.ErrCast()
   534  			}
   535  
   536  			verbose, _, _ := res.Request().Option("v").Bool()
   537  
   538  			marshal := func(v interface{}) (io.Reader, error) {
   539  				obj, ok := v.(*notif.QueryEvent)
   540  				if !ok {
   541  					return nil, u.ErrCast()
   542  				}
   543  
   544  				buf := new(bytes.Buffer)
   545  				if verbose {
   546  					fmt.Fprintf(buf, "%s: ", time.Now().Format("15:04:05.000"))
   547  				}
   548  				switch obj.Type {
   549  				case notif.FinalPeer:
   550  					if verbose {
   551  						fmt.Fprintf(buf, "* closest peer %s\n", obj.ID)
   552  					}
   553  				case notif.PeerResponse:
   554  					if verbose {
   555  						fmt.Fprintf(buf, "* %s says use ", obj.ID)
   556  						for _, p := range obj.Responses {
   557  							fmt.Fprintf(buf, "%s ", p.ID)
   558  						}
   559  						fmt.Fprintln(buf)
   560  					}
   561  				case notif.SendingQuery:
   562  					if verbose {
   563  						fmt.Fprintf(buf, "* querying %s\n", obj.ID)
   564  					}
   565  				case notif.QueryError:
   566  					fmt.Fprintf(buf, "error: %s\n", obj.Extra)
   567  				case notif.Value:
   568  					fmt.Fprintf(buf, "storing value at %s\n", obj.ID)
   569  				default:
   570  					fmt.Fprintf(buf, "unrecognized event type: %d\n", obj.Type)
   571  				}
   572  				return buf, nil
   573  			}
   574  
   575  			return &cmds.ChannelMarshaler{
   576  				Channel:   outChan,
   577  				Marshaler: marshal,
   578  				Res:       res,
   579  			}, nil
   580  		},
   581  	},
   582  	Type: notif.QueryEvent{},
   583  }