@@ -3,25 +3,29 @@ package rct
33import (
44 "fmt"
55 "net"
6+ "sync"
67 "time"
78)
89
9- // DialTimeout is the default cache for connecting to a RCT device
10- var DialTimeout = time .Second * 5
10+ var (
11+ // DialTimeout is the default cache for connecting to a RCT device
12+ DialTimeout = time .Second * 5
13+
14+ // Map of active connections
15+ connectionCache = make (map [string ]* Connection )
16+ )
1117
1218// Connection to a RCT device
1319type Connection struct {
14- host string
15- conn net. Conn
16- builder * DatagramBuilder
17- parser * DatagramParser
18- cache * Cache
20+ mu sync. Mutex
21+ host string
22+ conn net. Conn
23+ parser * DatagramParser
24+ cache * Cache
1925}
2026
21- // Map of active connections
22- var connectionCache map [string ]* Connection = make (map [string ]* Connection )
23-
24- // Creates a new connection to a RCT device at the given address
27+ // Creates a new connection to a RCT device at the given address.
28+ // Must not be called concurrently.
2529func NewConnection (host string , cache time.Duration ) (* Connection , error ) {
2630 if conn , ok := connectionCache [host ]; ok {
2731 if conn .conn != nil { // there might be dead connection in the cache, e.g. when connection was disconnected
@@ -30,10 +34,9 @@ func NewConnection(host string, cache time.Duration) (*Connection, error) {
3034 }
3135
3236 conn := & Connection {
33- host : host ,
34- builder : NewDatagramBuilder (),
35- parser : NewDatagramParser (),
36- cache : NewCache (cache ),
37+ host : host ,
38+ parser : NewDatagramParser (),
39+ cache : NewCache (cache ),
3740 }
3841
3942 if err := conn .connect (); err != nil {
@@ -59,7 +62,13 @@ func (c *Connection) Close() {
5962}
6063
6164// Sends the given RCT datagram via the connection
62- func (c * Connection ) Send (rdb * DatagramBuilder ) (n int , err error ) {
65+ func (c * Connection ) Send (rdb * DatagramBuilder ) (int , error ) {
66+ c .mu .Lock ()
67+ defer c .mu .Unlock ()
68+ return c .send (rdb )
69+ }
70+
71+ func (c * Connection ) send (rdb * DatagramBuilder ) (int , error ) {
6372 // ensure active connection
6473 if c .conn == nil {
6574 if err := c .connect (); err != nil {
@@ -68,8 +77,7 @@ func (c *Connection) Send(rdb *DatagramBuilder) (n int, err error) {
6877 }
6978
7079 // fmt.Printf("Sending %v\n", c.Builder.String())
71- n , err = c .conn .Write (rdb .Bytes ())
72-
80+ n , err := c .conn .Write (rdb .Bytes ())
7381 // single retry on error when sending
7482 if err != nil {
7583 // fmt.Printf("Read %d bytes error %v\n", n, err)
@@ -85,7 +93,14 @@ func (c *Connection) Send(rdb *DatagramBuilder) (n int, err error) {
8593}
8694
8795// Receives an RCT response via the connection
88- func (c * Connection ) Receive () (dg * Datagram , err error ) {
96+ func (c * Connection ) Receive () (* Datagram , error ) {
97+ c .mu .Lock ()
98+ defer c .mu .Unlock ()
99+ return c .receive ()
100+ }
101+
102+ // Receives an RCT response via the connection
103+ func (c * Connection ) receive () (dg * Datagram , err error ) {
89104 // ensure active connection
90105 if c .conn == nil {
91106 if err := c .connect (); err != nil {
@@ -108,17 +123,21 @@ func (c *Connection) Receive() (dg *Datagram, err error) {
108123}
109124
110125// Queries the given identifier on the RCT device, returning its value as a datagram
111- func (c * Connection ) Query (id Identifier ) (dg * Datagram , err error ) {
126+ func (c * Connection ) Query (id Identifier ) (* Datagram , error ) {
127+ c .mu .Lock ()
128+ defer c .mu .Unlock ()
129+
112130 if dg , ok := c .cache .Get (id ); ok {
113131 return dg , nil
114132 }
115- c .builder .Build (& Datagram {Read , id , nil })
116- _ , err = c .Send (c .builder )
117- if err != nil {
133+
134+ builder := NewDatagramBuilder ()
135+ builder .Build (& Datagram {Read , id , nil })
136+ if _ , err := c .send (builder ); err != nil {
118137 return nil , err
119138 }
120139
121- dg , err = c .Receive ()
140+ dg , err : = c .receive ()
122141 if err != nil {
123142 return nil , err
124143 }
0 commit comments