package peer import ( "fmt" "log" "runtime/debug" "sync/atomic" "time" ) type connHandler struct { // Communication. mediatorUpdates chan byte peerUpdates chan peerUpdate pings chan wrapper[Ping] pongs chan wrapper[Pong] data *connData } func newConnHandler( server bool, peerIP byte, routes [MAX_IP]*atomic.Pointer[route], encPrivKey []byte, sender *safeConnSender, ) *connHandler { d := &connData{ server: server, pingTimer: time.NewTimer(pingInterval), timeoutTimer: time.NewTimer(timeoutInterval), routes: routes, route: routes[peerIP], peerIP: peerIP, encPrivKey: encPrivKey, buf: make([]byte, BUFFER_SIZE), sender: sender, } h := &connHandler{ mediatorUpdates: make(chan byte, 1), peerUpdates: make(chan peerUpdate, 1), pings: make(chan wrapper[Ping], 1), pongs: make(chan wrapper[Pong], 1), data: d, } go h.mainLoop() return h } func (h *connHandler) mainLoop() { defer func() { if r := recover(); r != nil { fmt.Println("stacktrace from panic: \n" + string(debug.Stack())) } }() var ( data = h.data state = newConnNull(data) name = state.Name() ) for { select { case update := <-h.peerUpdates: state = data.HandlePeerUpdate(state, update) case w := <-h.pings: state = state.HandlePing(w) case w := <-h.pongs: state = state.HandlePong(w) case <-data.pingTimer.C: data.HandleSendPing() case <-data.timeoutTimer.C: log.Printf("[%s] Connection timeout.", state.Name()) state = state.HandleTimeout() } if state.Name() != name { log.Printf("[%03d] STATE: %s", data.peerIP, state.Name()) name = state.Name() } } } func (c *connHandler) HandlePing(w wrapper[Ping]) { select { case c.pings <- w: default: } } func (c *connHandler) HandlePong(w wrapper[Pong]) { select { case c.pongs <- w: default: } } func (c *connHandler) UpdatePeer(update peerUpdate) { select { case c.peerUpdates <- update: default: } }