/
correspondent.go
115 lines (105 loc) · 3.07 KB
/
correspondent.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package mansbridge
import (
"log"
"math/rand"
"time"
)
type Correspondent struct {
agent *Agent
cache *cache
peers *peerList
wireService WireService
done chan bool
repliantRequest chan chan string //should this be part of the struct?
refreshInterval time.Duration
}
func NewCorrespondent(a *Agent, wireService WireService, refreshInterval int, seedIp string, cacheSize int) *Correspondent {
peers := newPeerList()
peers.add(seedIp)
doneChan := make(chan bool)
c := Correspondent{agent: a,
cache: newCache(cacheSize),
wireService: wireService,
peers: peers,
done: doneChan,
refreshInterval: time.Duration(refreshInterval),
repliantRequest: make(chan chan string)}
go c.listenForRemoteUpdates()
return &c
}
func (c *Correspondent) listenForRemoteUpdates() {
for msg := range c.wireService.GetNews() {
//if we aren't expecting a reply, we were
//the randomly selected remote, so send our
//cache over
repliantResponseCh := make(chan string)
c.repliantRequest <- repliantResponseCh
expectedRepliant := <-repliantResponseCh
if expectedRepliant != msg.Source {
log.Println("Msg from: " + msg.Source)
go c.wireService.SendNews(msg.Source, c.cache.getEntries())
} else {
//this is a reply, so we don't need to send our cache,
//because we already did
log.Println("Reply from: " + msg.Source)
}
var remoteNews []NewsItem
remoteTime := msg.CurrentTime
localTime := time.Now()
timeDiff := remoteTime.Sub(localTime)
for _, entry := range msg.Entries {
if entry.IpAddress != c.wireService.GetAddress() {
//normalize the time
entry.Timestamp = entry.Timestamp.Add(timeDiff)
//collect the non-local news to pass to the agent
remoteNews = append(remoteNews, entry.News)
//update the list of peers that we can send to
c.peers.add(entry.IpAddress)
}
}
//pass the entries up to the agent
c.agent.newsUpdate(remoteNews)
//add and refresh cache
c.cache.addEntries(msg.Entries...)
c.cache.resize()
}
}
func (c *Correspondent) StartReporting() {
tick := time.NewTicker(time.Second * c.refreshInterval).C
expectedRepliant := ""
for {
select {
case <-tick:
log.Println("Getting new news...")
//step 1, add news to cache
news := c.agent.getNews()
if len(news.AgentId) > 0 {
entry := Entry{IpAddress: c.wireService.GetAddress(),
Timestamp: time.Now(),
News: news}
c.cache.addEntries(entry)
//step 2, find a random peer
peer := findPeer(c.peers.getAll())
//step 3, send cache to peer
log.Println("Sending cache to: " + peer)
c.wireService.SendNews(peer, c.cache.getEntries())
//keep track of who we sent to, so we can expect a response
expectedRepliant = peer
}
case ch := <-c.repliantRequest:
ch <- expectedRepliant
expectedRepliant = ""
case <-c.done:
log.Println("Done")
return
}
}
}
func (c *Correspondent) StopReporting() {
c.done <- true
}
func findPeer(peers []string) string {
rand.Seed(time.Now().Unix())
idx := rand.Intn(len(peers)-0) + 0
return peers[idx]
}