Skip to content

Commit 26fe766

Browse files
committed
add connect timeout for client
1 parent 108b758 commit 26fe766

File tree

2 files changed

+47
-14
lines changed

2 files changed

+47
-14
lines changed

client.go

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,17 @@ const (
5151
const (
5252
// RootNodeID is what sclang uses as the root node ID. See http://doc.sccode.org/Classes/RootNode.html.
5353
RootNodeID = int32(0)
54+
5455
// DefaultGroupID is what sclang uses for the default group ID. See http://doc.sccode.org/Reference/default_group.html.
5556
DefaultGroupID = int32(1)
57+
5658
// DefaultLocalAddr is the listening address for DefaultClient.
5759
DefaultLocalAddr = "0.0.0.0:57110"
60+
5861
// DefaultScsynthAddr is the remote address for DefaultClient.
5962
DefaultScsynthAddr = "0.0.0.0:57120"
63+
64+
DefaultConnectTimeout = time.Second
6065
)
6166

6267
// Common errors.
@@ -89,7 +94,7 @@ const numDoneHandlers = 8
8994
// NewClient creates a new SuperCollider client.
9095
// The client will bind to the provided address and port
9196
// to receive messages from scsynth.
92-
func NewClient(network, local, scsynth string) (*Client, error) {
97+
func NewClient(network, local, scsynth string, timeout time.Duration) (*Client, error) {
9398
addr, err := net.ResolveUDPAddr(network, local)
9499
if err != nil {
95100
return nil, err
@@ -102,7 +107,7 @@ func NewClient(network, local, scsynth string) (*Client, error) {
102107
addr: addr,
103108
nextSynthID: 1000,
104109
}
105-
if err := c.Connect(scsynth); err != nil {
110+
if err := c.Connect(scsynth, timeout); err != nil {
106111
return nil, err
107112
}
108113
return c, nil
@@ -118,7 +123,7 @@ func DefaultClient() (*Client, error) {
118123
var err error
119124

120125
if defaultClient == nil {
121-
defaultClient, err = NewClient("udp", DefaultLocalAddr, DefaultScsynthAddr)
126+
defaultClient, err = NewClient("udp", DefaultLocalAddr, DefaultScsynthAddr, DefaultConnectTimeout)
122127
if err != nil {
123128
return nil, err
124129
}
@@ -131,17 +136,30 @@ func DefaultClient() (*Client, error) {
131136
}
132137

133138
// Connect connects to an scsynth instance via UDP.
134-
func (c *Client) Connect(addr string) error {
139+
func (c *Client) Connect(addr string, timeout time.Duration) error {
135140
raddr, err := net.ResolveUDPAddr("udp", addr)
136141
if err != nil {
137142
return err
138143
}
139144

140-
oscConn, err := osc.DialUDP("udp", c.addr, raddr)
141-
if err != nil {
142-
return err
145+
// Attempt connection with a timeout.
146+
var (
147+
start = time.Now()
148+
timedOut = true
149+
)
150+
for time.Now().Sub(start) < timeout {
151+
oscConn, err := osc.DialUDP("udp", c.addr, raddr)
152+
if err != nil {
153+
time.Sleep(100 * time.Millisecond)
154+
continue
155+
}
156+
c.oscConn = oscConn
157+
timedOut = false
158+
break
159+
}
160+
if timedOut {
161+
return errors.New("connection timeout")
143162
}
144-
c.oscConn = oscConn
145163

146164
// listen for OSC messages
147165
go func() {

server.go

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,32 @@ import (
44
"fmt"
55
"os/exec"
66
"strconv"
7+
"time"
78
)
89

10+
// DefaultServerPort is the default listening port for scsynth.
11+
const DefaultServerPort = 57120
12+
913
// Server represents a running instance of scsynth.
1014
type Server struct {
1115
*exec.Cmd
1216

13-
Network string
14-
Port int
17+
Network string
18+
Port int
19+
StartTimeout time.Duration
1520
}
1621

1722
// args gets the command line args to scsynth
1823
func (s *Server) args() ([]string, error) {
24+
// Get the port.
25+
if s.Port <= 0 {
26+
s.Port = DefaultServerPort
27+
}
28+
portArg := strconv.FormatInt(int64(s.Port), 10)
29+
30+
// Create the args slice.
1931
args := []string{}
2032

21-
var (
22-
portArg = strconv.FormatInt(int64(s.Port), 10)
23-
)
2433
switch s.Network {
2534
default:
2635
return nil, fmt.Errorf("unrecognized network type: %s", s.Network)
@@ -40,7 +49,13 @@ func (s *Server) Start() error {
4049
return err
4150
}
4251
s.Cmd = exec.Command(ServerPath, args...)
43-
return s.Cmd.Start()
52+
if err := s.Cmd.Start(); err != nil {
53+
return err
54+
}
55+
56+
// Wait until the server returns a status.
57+
_, err = NewClient(s.Network, "0.0.0.0:0", fmt.Sprintf("0.0.0.0:%d", s.Port), 5*time.Second)
58+
return err
4459
}
4560

4661
// Stop stops a running server.

0 commit comments

Comments
 (0)