-
Notifications
You must be signed in to change notification settings - Fork 9
/
pingpong_example_test.go
129 lines (116 loc) · 2.78 KB
/
pingpong_example_test.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package osc
import (
"errors"
"fmt"
"log"
"net"
"time"
)
func Example_pingPong() {
errChan := make(chan error)
// Setup the server.
laddr, err := net.ResolveUDPAddr("udp", "127.0.0.1:0")
if err != nil {
log.Fatal(err)
}
server, err := ListenUDP("udp", laddr)
if err != nil {
log.Fatal(err)
}
// Run the server in a new goroutine.
go serverDispatch(server, errChan)
// Setup the client.
raddr, err := net.ResolveUDPAddr("udp", server.LocalAddr().String())
if err != nil {
log.Fatal(err)
}
client, err := DialUDP("udp", nil, raddr)
if err != nil {
log.Fatal(err)
}
var (
pongChan = make(chan struct{})
clientCloseChan = make(chan struct{})
)
// Clients are also servers!
go clientDispatch(client, errChan, pongChan, clientCloseChan)
// Send the ping message, wait for the pong, then close both connections.
if err := client.Send(Message{Address: "/ping"}); err != nil {
log.Fatal(err)
}
if err := waitPong(pongChan, errChan); err != nil {
log.Fatal(err)
}
if err := client.Send(Message{Address: "/close"}); err != nil {
log.Fatal(err)
}
if err := waitErr(errChan); err != nil {
log.Fatal(err)
}
if err := waitClose(clientCloseChan, errChan); err != nil {
log.Fatal(err)
}
// Output:
// Server received ping.
// Client received pong.
// Server closing.
// Client closing.
}
func serverDispatch(server *UDPConn, errChan chan error) {
errChan <- server.Serve(1, PatternMatching{
"/ping": Method(func(msg Message) error {
fmt.Println("Server received ping.")
return server.SendTo(msg.Sender, Message{Address: "/pong"})
}),
"/close": Method(func(msg Message) error {
if err := server.SendTo(msg.Sender, Message{Address: "/close"}); err != nil {
_ = server.Close()
return err
}
fmt.Println("Server closing.")
return server.Close()
}),
})
}
func clientDispatch(client Conn, errChan chan error, pongChan chan struct{}, closeChan chan struct{}) {
errChan <- client.Serve(1, PatternMatching{
"/pong": Method(func(msg Message) error {
fmt.Println("Client received pong.")
close(pongChan)
return nil
}),
"/close": Method(func(msg Message) error {
fmt.Println("Client closing.")
close(closeChan)
return client.Close()
}),
})
}
func waitPong(pongChan chan struct{}, errChan chan error) error {
select {
case <-time.After(2 * time.Second):
return errors.New("timeout")
case err := <-errChan:
if err != nil {
return err
}
case <-pongChan:
}
return nil
}
func waitErr(errChan chan error) error {
select {
case <-time.After(2 * time.Second):
return errors.New("timeout")
case err := <-errChan:
return err
}
}
func waitClose(closeChan chan struct{}, errChan chan error) error {
select {
case <-time.After(2 * time.Second):
return errors.New("timeout")
case <-closeChan:
}
return nil
}