func (spi *Spider) Stimulate() bool {
	stimulater, ok := spi.crawler.(dht.Stimulater)
	if ok {
		stimulater.Stimulate()
	}
	return ok
}
Stimulate will Stimulate the spider when Crawler is Stimulater and returns true.
else do nothing and returns false.
package btlet
import (
	"context"
	"errors"
	"fmt"
	"net"
	"time"
	"github.com/neoql/btlet/bt"
	"github.com/neoql/btlet/dht"
	"github.com/neoql/btlet/tools"
)
type Pipeline interface {
	Has(string) bool
	DisposeMeta(string, bt.RawMeta)
}
type PipelineX interface {
	Pipeline
	DisposeMetaAndTracker(string, bt.RawMeta, []string)
	PullTrackerList(string) ([]string, bool)
	AppendTracker(string, []string)
}
type Spider struct {
	crawler dht.Crawler
}
func NewSpider() *Spider {
	return &Spider{}
}
func (spi *Spider) Use(crawler dht.Crawler) {
	spi.crawler = crawler
}
func (spi *Spider) UseSybilCrawler() {
	spi.Use(dht.NewSybilCrawler("0.0.0.0:6881"))
}
func (spi *Spider) LimitSybilCrawler(limit int) {
	c := dht.NewSybilCrawler("0.0.0.0:6881")
	c.SetMaxWorkers(limit)
	spi.Use(c)
}
func (spi *Spider) Run(ctx context.Context, pipeline Pipeline) error {
	if spi.crawler == nil {
		spi.UseSybilCrawler()
	}
	return spi.crawler.Crawl(ctx, func(infoHash string, ip net.IP, port int) {
		if pipeline.Has(infoHash) {
			return
		}
		fctx, cancel := context.WithTimeout(ctx, time.Minute*5)
		defer cancel()
		meta, err := bt.FetchMetadata(fctx, infoHash, fmt.Sprintf("%s:%d", ip, port))
		if err != nil {
			return
		}
		pipeline.DisposeMeta(infoHash, meta)
	})
}