-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Expand file tree
/
Copy pathmain.go
More file actions
144 lines (116 loc) · 3.54 KB
/
Copy pathmain.go
File metadata and controls
144 lines (116 loc) · 3.54 KB
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package main
import (
"bytes"
"encoding/json"
"flag"
"fmt"
"log"
"net"
"net/http"
"sync"
"sync/atomic"
treefarm "github.com/oapi-codegen/oapi-codegen/v2/examples/callback"
)
// trees and cities for our planting requests
var treeKinds = []string{
"oak", "maple", "pine", "birch", "willow",
"cedar", "elm", "ash", "cherry", "walnut",
}
var cities = []string{
"Providence", "Austin", "Denver", "Seattle", "Chicago",
"Boston", "Miami", "Nashville", "Savannah", "Mountain View",
}
// CallbackReceiver implements treefarm.CallbackReceiverInterface.
type CallbackReceiver struct {
received atomic.Int32
total int
done chan struct{}
once sync.Once
mu sync.Mutex
ordinals map[string]int // UUID string -> 1-based planting order
}
var _ treefarm.CallbackReceiverInterface = (*CallbackReceiver)(nil)
func NewCallbackReceiver(total int) *CallbackReceiver {
return &CallbackReceiver{
total: total,
done: make(chan struct{}),
ordinals: make(map[string]int),
}
}
func (cr *CallbackReceiver) Register(id string, ordinal int) {
cr.mu.Lock()
cr.ordinals[id] = ordinal
cr.mu.Unlock()
}
func (cr *CallbackReceiver) HandleTreePlantedCallback(w http.ResponseWriter, r *http.Request) {
var result treefarm.TreePlantingResult
if err := json.NewDecoder(r.Body).Decode(&result); err != nil {
log.Printf("Error decoding callback: %v", err)
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
cr.mu.Lock()
ordinal := cr.ordinals[result.ID.String()]
cr.mu.Unlock()
n := cr.received.Add(1)
log.Printf("Callback %d/%d received: tree #%d success=%v", n, cr.total, ordinal, result.Success)
w.WriteHeader(http.StatusOK)
if int(n) >= cr.total {
cr.once.Do(func() { close(cr.done) })
}
}
func main() {
serverAddr := flag.String("server", "http://localhost:8080", "Tree farm server address")
flag.Parse()
const numTrees = 10
// Start callback receiver on an ephemeral port.
receiver := NewCallbackReceiver(numTrees)
mux := http.NewServeMux()
mux.Handle("/tree_callback", treefarm.TreePlantedCallbackHandler(receiver, nil))
listener, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
log.Fatalf("Failed to listen: %v", err)
}
callbackPort := listener.Addr().(*net.TCPAddr).Port
callbackURL := fmt.Sprintf("http://localhost:%d/tree_callback", callbackPort)
log.Printf("Callback receiver listening on port %d", callbackPort)
go func() {
if err := http.Serve(listener, mux); err != nil {
log.Printf("Callback server stopped: %v", err)
}
}()
// Send 10 tree planting requests.
client := &http.Client{}
for i := range numTrees {
req := treefarm.TreePlantingRequest{
Kind: treeKinds[i],
Location: cities[i],
CallbackURL: callbackURL,
}
body, err := json.Marshal(req)
if err != nil {
log.Fatalf("Failed to marshal request: %v", err)
}
resp, err := client.Post(
*serverAddr+"/api/plant_tree",
"application/json",
bytes.NewReader(body),
)
if err != nil {
log.Fatalf("Failed to plant tree %d: %v", i+1, err)
}
var accepted treefarm.TreeWithID
if err := json.NewDecoder(resp.Body).Decode(&accepted); err != nil {
_ = resp.Body.Close()
log.Fatalf("Failed to decode response: %v", err)
}
_ = resp.Body.Close()
receiver.Register(accepted.ID.String(), i+1)
log.Printf("Planted tree %d/%d: id=%s kind=%q location=%q",
i+1, numTrees, accepted.ID, accepted.Kind, accepted.Location)
}
log.Printf("All %d trees planted, waiting for callbacks...", numTrees)
// Wait for all callbacks.
<-receiver.done
log.Printf("All %d callbacks received, done!", numTrees)
}