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 }