providers.go 2.64 KB
Newer Older
1 2 3 4 5
package dht

import (
	"time"

6 7 8
	ctxgroup "github.com/ipfs/go-ipfs/Godeps/_workspace/src/github.com/jbenet/go-ctxgroup"
	peer "github.com/ipfs/go-ipfs/p2p/peer"
	u "github.com/ipfs/go-ipfs/util"
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
9

10
	context "github.com/ipfs/go-ipfs/Godeps/_workspace/src/golang.org/x/net/context"
11 12
)

13 14 15 16 17
type providerInfo struct {
	Creation time.Time
	Value    peer.ID
}

18 19
type ProviderManager struct {
	providers map[u.Key][]*providerInfo
20 21 22
	local     map[u.Key]struct{}
	lpeer     peer.ID
	getlocal  chan chan []u.Key
23 24
	newprovs  chan *addProv
	getprovs  chan *getProv
25
	period    time.Duration
26
	ctxgroup.ContextGroup
27 28 29
}

type addProv struct {
30
	k   u.Key
31
	val peer.ID
32 33 34
}

type getProv struct {
35
	k    u.Key
36
	resp chan []peer.ID
37 38
}

Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
39
func NewProviderManager(ctx context.Context, local peer.ID) *ProviderManager {
40 41 42 43
	pm := new(ProviderManager)
	pm.getprovs = make(chan *getProv)
	pm.newprovs = make(chan *addProv)
	pm.providers = make(map[u.Key][]*providerInfo)
44 45
	pm.getlocal = make(chan chan []u.Key)
	pm.local = make(map[u.Key]struct{})
46
	pm.ContextGroup = ctxgroup.WithContext(ctx)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
47 48

	pm.Children().Add(1)
49
	go pm.run()
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
50

51 52 53 54
	return pm
}

func (pm *ProviderManager) run() {
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
55 56
	defer pm.Children().Done()

57 58 59 60
	tick := time.NewTicker(time.Hour)
	for {
		select {
		case np := <-pm.newprovs:
61
			if np.val == pm.lpeer {
62 63
				pm.local[np.k] = struct{}{}
			}
64 65 66 67 68
			pi := new(providerInfo)
			pi.Creation = time.Now()
			pi.Value = np.val
			arr := pm.providers[np.k]
			pm.providers[np.k] = append(arr, pi)
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
69

70
		case gp := <-pm.getprovs:
71
			var parr []peer.ID
72 73 74 75 76
			provs := pm.providers[gp.k]
			for _, p := range provs {
				parr = append(parr, p.Value)
			}
			gp.resp <- parr
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
77

78 79 80 81 82 83
		case lc := <-pm.getlocal:
			var keys []u.Key
			for k, _ := range pm.local {
				keys = append(keys, k)
			}
			lc <- keys
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
84

85 86 87 88
		case <-tick.C:
			for k, provs := range pm.providers {
				var filtered []*providerInfo
				for _, p := range provs {
89
					if time.Now().Sub(p.Creation) < time.Hour*24 {
90 91 92 93 94
						filtered = append(filtered, p)
					}
				}
				pm.providers[k] = filtered
			}
Juan Batiz-Benet's avatar
Juan Batiz-Benet committed
95 96

		case <-pm.Closing():
97 98 99 100 101
			return
		}
	}
}

102 103
func (pm *ProviderManager) AddProvider(ctx context.Context, k u.Key, val peer.ID) {
	prov := &addProv{
104
		k:   k,
105 106
		val: val,
	}
107 108 109 110
	select {
	case pm.newprovs <- prov:
	case <-ctx.Done():
	}
111 112
}

113
func (pm *ProviderManager) GetProviders(ctx context.Context, k u.Key) []peer.ID {
114 115
	gp := &getProv{
		k:    k,
116
		resp: make(chan []peer.ID, 1), // buffered to prevent sender from blocking
117
	}
118
	select {
Brian Tiger Chow's avatar
Brian Tiger Chow committed
119 120
	case <-ctx.Done():
		return nil
121
	case pm.getprovs <- gp:
Brian Tiger Chow's avatar
Brian Tiger Chow committed
122 123
	}
	select {
124 125
	case <-ctx.Done():
		return nil
Brian Tiger Chow's avatar
Brian Tiger Chow committed
126 127
	case peers := <-gp.resp:
		return peers
128
	}
129
}
130

131 132 133 134 135
func (pm *ProviderManager) GetLocal() []u.Key {
	resp := make(chan []u.Key)
	pm.getlocal <- resp
	return <-resp
}