github.com/jmigpin/editor@v1.6.0/core/godebug/debug/server.go (about)

     1  package debug
     2  
     3  import (
     4  	"errors"
     5  	"io"
     6  	"io/ioutil"
     7  	"log"
     8  	"net"
     9  	"sync"
    10  	"time"
    11  )
    12  
    13  // init() functions declared across multiple files in a package are processed in alphabetical order of the file name
    14  func init() {
    15  	if hasGenConfig {
    16  		RegisterStructsForEncodeDecode(encoderId)
    17  		StartServer()
    18  	}
    19  }
    20  
    21  //----------
    22  
    23  // Vars populated at init (generated at compile).
    24  var hasGenConfig bool
    25  var encoderId string
    26  var ServerNetwork string
    27  var ServerAddress string
    28  var annotatorFilesData []*AnnotatorFileData // all debug data
    29  
    30  var syncSend bool              // don't send in chunks (usefull to get msgs before crash)
    31  var acceptOnlyFirstClient bool // avoid possible hanging progs waiting for another connection to continue debugging (most common case)
    32  var stringifyBytesRunes bool   // output "abc" instead of [97 98 99]
    33  var hasSrcLines bool           // in case of panic, show warning about srclines
    34  
    35  //----------
    36  
    37  //var logger = log.New(os.Stdout, "debug: ", log.Llongfile)
    38  //var logger = log.New(os.Stdout, "debug: ", 0)
    39  var logger = log.New(ioutil.Discard, "debug: ", 0)
    40  
    41  const chunkSendRate = 15       // per second
    42  const chunkSendQSize = 512     // msgs queueing to be sent
    43  const chunkSendNowNMsgs = 2048 // don't wait for send rate, send now (memory)
    44  
    45  //----------
    46  
    47  type Server struct {
    48  	listen struct {
    49  		ln       net.Listener
    50  		loopWait sync.WaitGroup
    51  	}
    52  	conn struct { // currently only handling one conn at a time
    53  		sync.Mutex
    54  		haveConn *sync.Cond // cc!=nil
    55  		cc       *CConn
    56  	}
    57  	toSend       chan interface{}
    58  	sendLoopWait sync.WaitGroup
    59  }
    60  
    61  func NewServer() (*Server, error) {
    62  	srv := &Server{}
    63  	srv.conn.haveConn = sync.NewCond(&srv.conn)
    64  
    65  	// start listening
    66  	ln, err := net.Listen(ServerNetwork, ServerAddress)
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  	srv.listen.ln = ln
    71  	logger.Print("listening")
    72  
    73  	// setup sending
    74  	qsize := chunkSendQSize
    75  	if syncSend {
    76  		qsize = 0
    77  	}
    78  	srv.toSend = make(chan interface{}, qsize)
    79  	srv.sendLoopWait.Add(1)
    80  	go func() {
    81  		defer srv.sendLoopWait.Done()
    82  		srv.sendLoop()
    83  	}()
    84  
    85  	// accept connections
    86  	srv.listen.loopWait.Add(1)
    87  	go func() {
    88  		defer srv.listen.loopWait.Done()
    89  		srv.acceptClientLoop()
    90  	}()
    91  
    92  	// wait for one client to be sendready before returning
    93  	srv.waitForCConnReady()
    94  	logger.Println("server init done (client ready)")
    95  
    96  	return srv, nil
    97  }
    98  
    99  //----------
   100  
   101  func (srv *Server) acceptClientLoop() {
   102  	defer logger.Println("end accept client loop")
   103  	for {
   104  		// accept client
   105  		logger.Println("waiting for client")
   106  		conn, err := srv.listen.ln.Accept()
   107  		if err != nil {
   108  			logger.Printf("accept error: (%T) %v", err, err)
   109  
   110  			// unable to accept (ex: server was closed)
   111  			if operr, ok := err.(*net.OpError); ok {
   112  				if operr.Op == "accept" {
   113  					return
   114  				}
   115  			}
   116  
   117  			continue
   118  		}
   119  
   120  		logger.Println("got client")
   121  		srv.handleConn(conn)
   122  
   123  		// don't receive anymore connections
   124  		if acceptOnlyFirstClient {
   125  			logger.Println("no more clients (accepting only first)")
   126  			return
   127  		}
   128  	}
   129  }
   130  
   131  //----------
   132  
   133  func (srv *Server) handleConn(conn net.Conn) {
   134  	srv.conn.Lock()
   135  	defer srv.conn.Unlock()
   136  
   137  	// currently only handling one client at a time
   138  	if srv.conn.cc != nil { // already connected, reject
   139  		_ = conn.Close()
   140  		return
   141  	}
   142  
   143  	srv.conn.cc = NewCConn(srv, conn)
   144  	srv.conn.haveConn.Broadcast()
   145  }
   146  func (srv *Server) closeConnection() error {
   147  	srv.conn.Lock()
   148  	defer srv.conn.Unlock()
   149  	if srv.conn.cc != nil {
   150  		cc := srv.conn.cc
   151  		srv.conn.cc = nil // remove connection from server
   152  		return cc.close()
   153  	}
   154  	return nil
   155  }
   156  
   157  //----------
   158  
   159  func (srv *Server) waitForCConn() *CConn {
   160  	cc := srv.conn.cc
   161  	if cc == nil {
   162  		srv.conn.Lock()
   163  		defer srv.conn.Unlock()
   164  		for srv.conn.cc == nil {
   165  			srv.conn.haveConn.Wait()
   166  		}
   167  		cc = srv.conn.cc
   168  	}
   169  	return cc
   170  }
   171  
   172  //----------
   173  
   174  func (srv *Server) Send(v *LineMsg) {
   175  	// simply add to a channel to allow program to continue
   176  	srv.toSend <- v
   177  }
   178  func (srv *Server) sendLoop() {
   179  	for {
   180  		v := <-srv.toSend
   181  		logger.Printf("tosend: %#v", v)
   182  		switch t := v.(type) {
   183  		case bool:
   184  			if t == false {
   185  				logger.Println("stopping send loop")
   186  				return
   187  			}
   188  		case *LineMsg:
   189  			cc := srv.waitForCConn()
   190  			cc.sendWhenReady(t)
   191  		}
   192  	}
   193  }
   194  
   195  //----------
   196  
   197  func (srv *Server) waitForCConnReady() {
   198  	cc := srv.waitForCConn()
   199  	cc.runWhenReady(func() {})
   200  }
   201  
   202  //----------
   203  
   204  func (srv *Server) Close() error {
   205  	logger.Println("closing server")
   206  	defer logger.Println("server closed")
   207  
   208  	// stop accepting more connections
   209  	err := srv.listen.ln.Close()
   210  	srv.listen.loopWait.Wait()
   211  
   212  	// stop getting values to send
   213  	srv.toSend <- false
   214  	srv.sendLoopWait.Wait()
   215  
   216  	_ = srv.closeConnection()
   217  
   218  	return err
   219  }
   220  
   221  //----------
   222  //----------
   223  //----------
   224  
   225  // Client connection.
   226  type CConn struct {
   227  	srv  *Server
   228  	conn net.Conn
   229  
   230  	state struct {
   231  		sync.Mutex
   232  		ready   *sync.Cond // have exchanged init data and can send
   233  		started bool
   234  		closed  bool
   235  	}
   236  
   237  	lines  []*LineMsg // inside lock if sending in chunks (vs syncsend)
   238  	chunks struct {
   239  		sync.Mutex
   240  		scheduled bool
   241  		sendWait  sync.WaitGroup
   242  		sent      time.Time
   243  	}
   244  }
   245  
   246  func NewCConn(srv *Server, conn net.Conn) *CConn {
   247  	cc := &CConn{srv: srv, conn: conn}
   248  	cc.state.ready = sync.NewCond(&cc.state)
   249  
   250  	// receive messages
   251  	go cc.receiveMsgsLoop()
   252  
   253  	return cc
   254  }
   255  
   256  func (cc *CConn) close() error {
   257  	logger.Println("closing client")
   258  	defer logger.Println("client closed")
   259  
   260  	cc.state.Lock()
   261  	defer cc.state.Unlock()
   262  	if cc.state.closed {
   263  		return nil
   264  	}
   265  	cc.state.closed = true
   266  
   267  	// wait for last msgs to be sent
   268  	cc.chunks.sendWait.Wait()
   269  
   270  	return cc.conn.Close() // stops receiveMsgsLoop
   271  }
   272  
   273  func (cc *CConn) closeFromServerWithErr(err error) {
   274  	err2 := cc.srv.closeConnection()
   275  	if err == nil {
   276  		err = err2
   277  	}
   278  
   279  	// connection ended gracefully by the client
   280  	if errors.Is(err, io.EOF) {
   281  		return
   282  	}
   283  	// unable to read (client was probably closed)
   284  	if operr, ok := err.(*net.OpError); ok {
   285  		if operr.Op == "read" {
   286  			return
   287  		}
   288  	}
   289  	// always print if the error reaches here
   290  	panic(err)
   291  	logger.Printf("error: %s", err)
   292  	return
   293  }
   294  
   295  //----------
   296  
   297  func (cc *CConn) receiveMsgsLoop() {
   298  	for {
   299  		msg, err := DecodeMessage(cc.conn)
   300  		if err != nil {
   301  			cc.closeFromServerWithErr(err)
   302  			return
   303  		}
   304  
   305  		// handle msg
   306  		switch t := msg.(type) {
   307  		case *ReqFilesDataMsg:
   308  			logger.Print("got reqfilesdata")
   309  			msg := &FilesDataMsg{Data: annotatorFilesData}
   310  			if err := cc.write(msg); err != nil {
   311  				cc.closeFromServerWithErr(err)
   312  				return
   313  			}
   314  		case *ReqStartMsg:
   315  			logger.Print("got reqstart")
   316  			cc.ready()
   317  		default:
   318  			// always print if there is a new msg type
   319  			log.Printf("todo: unexpected msg type: %T", t)
   320  		}
   321  	}
   322  }
   323  
   324  //----------
   325  
   326  func (cc *CConn) sendWhenReady(v *LineMsg) {
   327  	cc.runWhenReady(func() {
   328  		cc.send2(v)
   329  	})
   330  }
   331  func (cc *CConn) send2(v *LineMsg) {
   332  	if syncSend {
   333  		cc.lines = append(cc.lines, v)
   334  		cc.sendLines()
   335  	} else {
   336  		cc.sendLinesInChunks(v)
   337  	}
   338  }
   339  func (cc *CConn) sendLines() {
   340  	if len(cc.lines) == 0 {
   341  		return
   342  	}
   343  	if err := cc.write(cc.lines); err != nil {
   344  		cc.closeFromServerWithErr(err)
   345  		return
   346  	}
   347  	cc.lines = cc.lines[:0]
   348  }
   349  func (cc *CConn) sendLinesInChunks(v *LineMsg) {
   350  	cc.chunks.Lock()
   351  	defer cc.chunks.Unlock()
   352  
   353  	cc.lines = append(cc.lines, v)
   354  	if len(cc.lines) >= chunkSendNowNMsgs {
   355  		cc.sendLines()
   356  		return
   357  	}
   358  
   359  	if cc.chunks.scheduled {
   360  		return
   361  	}
   362  	cc.chunks.scheduled = true
   363  
   364  	cc.chunks.sendWait.Add(1)
   365  	go func() {
   366  		defer cc.chunks.sendWait.Done()
   367  
   368  		now := time.Now()
   369  		d := time.Second / time.Duration(chunkSendRate)
   370  		sd := cc.chunks.sent.Add(d).Sub(now)
   371  		cc.chunks.sent = now
   372  		//log.Println("sleeping", sd)
   373  		time.Sleep(sd)
   374  
   375  		cc.chunks.Lock()
   376  		defer cc.chunks.Unlock()
   377  		cc.chunks.scheduled = false
   378  		cc.sendLines()
   379  	}()
   380  }
   381  
   382  //----------
   383  
   384  func (cc *CConn) ready() {
   385  	cc.state.Lock()
   386  	defer cc.state.Unlock()
   387  	if !cc.state.started && !cc.state.closed {
   388  		cc.state.started = true
   389  		cc.state.ready.Broadcast()
   390  	}
   391  }
   392  func (cc *CConn) runWhenReady(fn func()) {
   393  	cc.state.Lock()
   394  	defer cc.state.Unlock()
   395  	for !cc.state.started && !cc.state.closed {
   396  		cc.state.ready.Wait()
   397  	}
   398  	if cc.state.started && !cc.state.closed {
   399  		fn()
   400  	}
   401  }
   402  
   403  //----------
   404  
   405  func (cc *CConn) write(v interface{}) error {
   406  	encoded, err := EncodeMessage(v)
   407  	if err != nil {
   408  		panic(err)
   409  	}
   410  	n, err := cc.conn.Write(encoded)
   411  	if err != nil {
   412  		return err
   413  	}
   414  	if n != len(encoded) {
   415  		logger.Printf("n!=len(encoded): %v %v\n", n, len(encoded))
   416  	}
   417  	return nil
   418  }