|
1 | 1 | package main |
2 | 2 |
|
3 | | -import ( |
4 | | - "crypto/ed25519" |
5 | | - "crypto/rand" |
6 | | - "fmt" |
7 | | - mathrand "math/rand" |
8 | | - "time" |
| 3 | +import "golang.org/x/tour/tree" |
9 | 4 |
|
10 | | - "github.com/brianvoe/gofakeit" |
11 | | -) |
| 5 | +// Walk walks the tree t sending all values |
| 6 | +// from the tree to the channel ch. |
| 7 | +func Walk(t *tree.Tree, ch chan int) |
12 | 8 |
|
13 | | -// Document stores text created by bureaucrat and have field for signature |
14 | | -type Document struct { |
15 | | - text string |
16 | | - sign []byte |
17 | | -} |
18 | | - |
19 | | -// Let's define three roles in our office: bureaucrat, executor and verifier |
20 | | - |
21 | | -// bureaucrat generates documents and take a rest after every document creation. |
22 | | -// as soon as bureaucrat gets signal (done channel is closed) to finish its work it stops |
23 | | -func bureaucrat(done <-chan struct{}, out chan<- *Document) int { |
24 | | - docs_total := 0 |
25 | | - for { |
26 | | - select { |
27 | | - case _ = <-done: |
28 | | - return docs_total |
29 | | - case out <- &Document{text: gofakeit.Sentence(9)}: |
30 | | - docs_total++ |
31 | | - // |
32 | | - |
33 | | - time.Sleep(time.Millisecond * time.Duration(mathrand.Intn(100))) |
34 | | - } |
35 | | - } |
36 | | -} |
37 | | - |
38 | | -// executor signs documents it receives and send the documents further |
39 | | -func executor(priv ed25519.PrivateKey, in <-chan *Document, out chan<- *Document) int { |
40 | | - docs_total := 0 |
41 | | - for doc := range in { |
42 | | - doc.sign = ed25519.Sign(priv, []byte(doc.text)) |
43 | | - docs_total++ |
44 | | - out <- doc |
45 | | - } |
46 | | - return docs_total |
47 | | -} |
48 | | - |
49 | | -// verifier checks signature in every document it receives and send the documents further |
50 | | -func verifier(pub ed25519.PublicKey, in <-chan *Document, out chan<- *Document) int { |
51 | | - docs_total := 0 |
52 | | - for doc := range in { |
53 | | - if ed25519.Verify(pub, []byte(doc.text), doc.sign) { |
54 | | - out <- doc |
55 | | - } |
56 | | - docs_total++ |
57 | | - } |
58 | | - return docs_total |
59 | | -} |
60 | | - |
61 | | -func fanoutProxy(in <-chan *Document, fakeIn chan *Document, out chan *Document) { |
62 | | - for msg := range in { |
63 | | - fakeIn <- msg |
64 | | - } |
65 | | - close(fakeIn) |
66 | | - close(out) |
67 | | -} |
68 | | - |
69 | | -// SpawnBureaucrat is generator function that spawns one bureaucrat, |
70 | | -// and returns channel with generated documents. Also handles channel lifecycle |
71 | | -func SpawnBureaucrat(done <-chan struct{}) <-chan *Document { |
72 | | - out := make(chan *Document) |
73 | | - go func() { |
74 | | - total := bureaucrat(done, out) |
75 | | - fmt.Println(total, "documents were created by Bureaucrat") |
76 | | - close(out) |
77 | | - }() |
78 | | - return out |
79 | | -} |
80 | | - |
81 | | -// SpawnExecutors is generator function that create n executors, |
82 | | -// fan out documents to executors from input channel, |
83 | | -// and returns channel with signed documents. Also handles channel lifecycle |
84 | | -func SpawnExecutors(n int, priv ed25519.PrivateKey, in <-chan *Document) <-chan *Document { |
85 | | - out := make(chan *Document) |
86 | | - fakeIn := make(chan *Document) |
87 | | - totals := make([]int, n) |
88 | | - // we must propagate closing of channels from INs to OUTs |
89 | | - // close() must be called only once |
90 | | - // we spawn multiple workers |
91 | | - // so we need one goroutine from that we can catch channel closing and close out channel |
92 | | - // for this purpose fanoutProxy |
93 | | - // fanoutProxy reads documents from IN channel, sends them to fakeIn |
94 | | - // If IN channel is closed it will close fakeIN and OUT, |
95 | | - // so executors will be closed gracefully, because of close(fakeIN) |
96 | | - // and close will be propagated further to Out channel |
97 | | - go fanoutProxy(in, fakeIn, out) |
98 | | - for i := 0; i < n; i++ { |
99 | | - go func(i int) { |
100 | | - totals[i] = executor(priv, fakeIn, out) |
101 | | - fmt.Println(totals[i], "documents were signed by Executor", i) // why it is not shown in output? |
102 | | - }(i) |
103 | | - } |
104 | | - |
105 | | - return out |
106 | | -} |
107 | | - |
108 | | -// SpawnExecutors is generator function that create one verifier, |
109 | | -// and returns channel with verified documents. Also handles channel lifecycle |
110 | | -func SpawnVerifier(pub ed25519.PublicKey, in <-chan *Document) <-chan *Document { |
111 | | - out := make(chan *Document) |
112 | | - go func() { |
113 | | - total := verifier(pub, in, out) |
114 | | - fmt.Println(total, "documents were verified by verifier") |
115 | | - close(out) |
116 | | - }() |
117 | | - return out |
118 | | -} |
| 9 | +// Same determines whether the trees |
| 10 | +// t1 and t2 contain the same values. |
| 11 | +func Same(t1, t2 *tree.Tree) bool |
119 | 12 |
|
120 | 13 | func main() { |
121 | | - // to get executors and verifier work we need to provide private and public keys |
122 | | - pub, priv, _ := ed25519.GenerateKey(rand.Reader) |
123 | | - |
124 | | - done := make(chan struct{}) |
125 | | - docsNew := SpawnBureaucrat(done) |
126 | | - docsSigned := SpawnExecutors(2, priv, docsNew) |
127 | | - docsVerified := SpawnVerifier(pub, docsSigned) |
128 | | - |
129 | | - // we don't want this to run infinitely, so we'll stop this by signaling bureaucrat to stop |
130 | | - go func(done chan struct{}) { |
131 | | - time.Sleep(3 * time.Second) |
132 | | - close(done) |
133 | | - // channel closing flow is: |
134 | | - // close(done) --> close(docsNew)--> [fanoutProxy] --> close(docsSigned) --> close(docsVerified) |
135 | | - }(done) |
136 | | - |
137 | | - // the whole structure will be like that: |
138 | | - // / [executor 1] \ |
139 | | - // [bureaucrat]---------| |--------[verifier]-------[range in main] |
140 | | - // \ [executor 2] / |
141 | | - |
142 | | - sentToNowhere := 0 |
143 | | - // nowhere emulation |
144 | | - for range docsVerified { |
145 | | - sentToNowhere++ |
146 | | - } |
147 | | - |
148 | | - fmt.Println(sentToNowhere, "documents were sent to nowhere") |
149 | 14 | } |
0 commit comments