@@ -31,11 +31,14 @@ import (
3131 "encoding/json"
3232 "fmt"
3333 "io"
34+ "net"
3435 "regexp"
3536 "strconv"
3637 "strings"
38+ "sync"
3739
3840 "github.com/arduino/go-properties-orderedmap"
41+ "github.com/hashicorp/go-multierror"
3942)
4043
4144// Port is a descriptor for a board port
@@ -62,7 +65,7 @@ type Monitor interface {
6265 Configure (parameterName string , value string ) error
6366
6467 // 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 )
6669
6770 // Close will close the currently open port and TCP/IP connection
6871 Close () error
@@ -80,6 +83,8 @@ type Server struct {
8083 userAgent string
8184 reqProtocolVersion int
8285 initialized bool
86+ clientConn net.Conn
87+ closeFuncMutex sync.Mutex
8388}
8489
8590// NewServer creates a new monitor server backed by the
@@ -126,7 +131,7 @@ func (d *Server) Run(in io.Reader, out io.Writer) error {
126131 case "OPEN" :
127132 d .open (fullCmd [5 :])
128133 case "CLOSE" :
129- d .close ()
134+ d .close ("" )
130135 case "QUIT" :
131136 d .impl .Quit ()
132137 d .outputChan <- messageOk ("quit" )
@@ -208,13 +213,76 @@ func (d *Server) configure(cmd string) {
208213}
209214
210215func (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+ }
216259}
217260
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+ }
218286}
219287
220288func (d * Server ) outputProcessor (outWriter io.Writer ) {
0 commit comments