package mockrouting import ( "context" "math/rand" "sync" "time" cid "gitlab.dms3.io/dms3/public/go-cid" ds "gitlab.dms3.io/dms3/public/go-datastore" dssync "gitlab.dms3.io/dms3/public/go-datastore/sync" "gitlab.dms3.io/p2p/go-p2p-core/peer" tnet "gitlab.dms3.io/p2p/go-p2p-testing/net" offline "gitlab.dms3.io/dms3/public/go-dms3-routing/offline" ) // server is the mockrouting.Client's private interface to the routing server type server interface { Announce(peer.AddrInfo, cid.Cid) error Providers(cid.Cid) []peer.AddrInfo Server } // s is an implementation of the private server interface type s struct { delayConf DelayConfig lock sync.RWMutex providers map[string]map[peer.ID]providerRecord } type providerRecord struct { Peer peer.AddrInfo Created time.Time } func (rs *s) Announce(p peer.AddrInfo, c cid.Cid) error { rs.lock.Lock() defer rs.lock.Unlock() k := c.KeyString() _, ok := rs.providers[k] if !ok { rs.providers[k] = make(map[peer.ID]providerRecord) } rs.providers[k][p.ID] = providerRecord{ Created: time.Now(), Peer: p, } return nil } func (rs *s) Providers(c cid.Cid) []peer.AddrInfo { rs.delayConf.Query.Wait() // before locking rs.lock.RLock() defer rs.lock.RUnlock() k := c.KeyString() var ret []peer.AddrInfo records, ok := rs.providers[k] if !ok { return ret } for _, r := range records { if time.Since(r.Created) > rs.delayConf.ValueVisibility.Get() { ret = append(ret, r.Peer) } } for i := range ret { j := rand.Intn(i + 1) ret[i], ret[j] = ret[j], ret[i] } return ret } func (rs *s) Client(p tnet.Identity) Client { return rs.ClientWithDatastore(context.Background(), p, dssync.MutexWrap(ds.NewMapDatastore())) } func (rs *s) ClientWithDatastore(_ context.Context, p tnet.Identity, datastore ds.Datastore) Client { return &client{ peer: p, vs: offline.NewOfflineRouter(datastore, MockValidator{}), server: rs, } }