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, ¬if.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, ¬if.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, ¬if.QueryEvent{ 306 Type: notif.QueryError, 307 Extra: err.Error(), 308 }) 309 return 310 } 311 312 notif.PublishQueryEvent(ctx, ¬if.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, ¬if.QueryEvent{ 411 Type: notif.QueryError, 412 Extra: err.Error(), 413 }) 414 } else { 415 notif.PublishQueryEvent(ctx, ¬if.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, ¬if.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 }