func (d *Diagnostics) HandleMessage(ctx context.Context, s inet.Stream) error { cr := ctxio.NewReader(ctx, s) cw := ctxio.NewWriter(ctx, s) r := ggio.NewDelimitedReader(cr, inet.MessageSizeMax) // maxsize w := ggio.NewDelimitedWriter(cw) // deserialize msg pmes := new(pb.Message) if err := r.ReadMsg(pmes); err != nil { log.Debugf("Failed to decode protobuf message: %v", err) return nil } // Print out diagnostic log.Infof("[peer: %s] Got message from [%s]\n", d.self.Pretty(), s.Conn().RemotePeer()) // Make sure we havent already handled this request to prevent loops if err := d.startDiag(pmes.GetDiagID()); err != nil { return nil } resp := newMessage(pmes.GetDiagID()) resp.Data = d.getDiagInfo().Marshal() if err := w.WriteMsg(resp); err != nil { log.Debugf("Failed to write protobuf message over stream: %s", err) return err } timeout := pmes.GetTimeoutDuration() if timeout < HopTimeoutDecrement { return fmt.Errorf("timeout too short: %s", timeout) } ctx, cancel := context.WithTimeout(ctx, timeout) defer cancel() pmes.SetTimeoutDuration(timeout - HopTimeoutDecrement) dpeers, err := d.getDiagnosticFromPeers(ctx, d.getPeers(), pmes) if err != nil { log.Debugf("diagnostic from peers err: %s", err) return err } for b := range dpeers { resp := newMessage(pmes.GetDiagID()) resp.Data = b.Marshal() if err := w.WriteMsg(resp); err != nil { log.Debugf("Failed to write protobuf message over stream: %s", err) return err } } return nil }