@@ -31,11 +31,14 @@ import (
31
31
"encoding/json"
32
32
"fmt"
33
33
"io"
34
+ "net"
34
35
"regexp"
35
36
"strconv"
36
37
"strings"
38
+ "sync"
37
39
38
40
"github.com/arduino/go-properties-orderedmap"
41
+ "github.com/hashicorp/go-multierror"
39
42
)
40
43
41
44
// Port is a descriptor for a board port
@@ -62,7 +65,7 @@ type Monitor interface {
62
65
Configure (parameterName string , value string ) error
63
66
64
67
// Open allows to open a communication with the board using TCP/IP
65
- Open (ipAddress string , boardPort string ) error
68
+ Open (boardPort string ) (io. ReadWriter , error )
66
69
67
70
// Close will close the currently open port and TCP/IP connection
68
71
Close () error
@@ -80,6 +83,8 @@ type Server struct {
80
83
userAgent string
81
84
reqProtocolVersion int
82
85
initialized bool
86
+ clientConn net.Conn
87
+ closeFuncMutex sync.Mutex
83
88
}
84
89
85
90
// NewServer creates a new monitor server backed by the
@@ -126,7 +131,7 @@ func (d *Server) Run(in io.Reader, out io.Writer) error {
126
131
case "OPEN" :
127
132
d .open (fullCmd [5 :])
128
133
case "CLOSE" :
129
- d .close ()
134
+ d .close ("" )
130
135
case "QUIT" :
131
136
d .impl .Quit ()
132
137
d .outputChan <- messageOk ("quit" )
@@ -208,13 +213,76 @@ func (d *Server) configure(cmd string) {
208
213
}
209
214
210
215
func (d * Server ) open (cmd string ) {
211
-
212
- }
213
-
214
- func (d * Server ) close () {
215
-
216
+ if ! d .initialized {
217
+ d .outputChan <- messageError ("open" , "Monitor not initialized" )
218
+ return
219
+ }
220
+ parameters := strings .SplitN (cmd , " " , 2 )
221
+ if len (parameters ) != 2 {
222
+ d .outputChan <- messageError ("open" , "Invalid OPEN command" )
223
+ return
224
+ }
225
+ address := parameters [0 ]
226
+ portName := parameters [1 ]
227
+ port , err := d .impl .Open (portName )
228
+ if err != nil {
229
+ d .outputChan <- messageError ("open" , err .Error ())
230
+ return
231
+ }
232
+ d .clientConn , err = net .Dial ("tcp" , address )
233
+ if err != nil {
234
+ d .impl .Close ()
235
+ d .outputChan <- messageError ("open" , err .Error ())
236
+ return
237
+ }
238
+ // io.Copy is used to bridge the Client's TCP connection to the port one and vice versa
239
+ go func () {
240
+ _ , err := io .Copy (port , d .clientConn ) // Copy is blocking, so we run it insiede a gorutine
241
+ if err != nil {
242
+ d .close (err .Error ())
243
+ } else {
244
+ d .close ("lost TCP/IP connection with the client!" )
245
+ }
246
+ }()
247
+ go func () {
248
+ _ , err := io .Copy (d .clientConn , port ) // Copy is blocking, so we run it insiede a gorutine
249
+ if err != nil {
250
+ d .close (err .Error ())
251
+ } else {
252
+ d .close ("lost connection with the port" )
253
+ }
254
+ }()
255
+ d .outputChan <- & message {
256
+ EventType : "open" ,
257
+ Message : "OK" ,
258
+ }
216
259
}
217
260
261
+ func (d * Server ) close (messageErr string ) {
262
+ d .closeFuncMutex .Lock ()
263
+ defer d .closeFuncMutex .Unlock ()
264
+ if d .clientConn == nil {
265
+ // TODO
266
+ // d.outputChan <- messageError("close", "port already closed")
267
+ return
268
+ }
269
+ connErr := d .clientConn .Close ()
270
+ portErr := d .impl .Close ()
271
+ d .clientConn = nil
272
+ if messageErr != "" {
273
+ d .outputChan <- messageError ("port_closed" , messageErr )
274
+ return
275
+ }
276
+ if connErr != nil || portErr != nil {
277
+ var errs * multierror.Error
278
+ errs = multierror .Append (errs , connErr , portErr )
279
+ d .outputChan <- messageError ("close" , errs .Error ())
280
+ return
281
+ }
282
+ d .outputChan <- & message {
283
+ EventType : "close" ,
284
+ Message : "OK" ,
285
+ }
218
286
}
219
287
220
288
func (d * Server ) outputProcessor (outWriter io.Writer ) {
0 commit comments