When preparing a tutorial for netxlite, I figured it is easier to tell people "hey, this is the package you should use for all low-level networking stuff" rather than introducing people to a set of packages working together where some piece of functionality is here and some other piece is there. Part of https://github.com/ooni/probe/issues/1591
		
			
				
	
	
		
			71 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			71 lines
		
	
	
		
			1.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Package errorsx contains error extensions.
 | |
| package errorsx
 | |
| 
 | |
| import (
 | |
| 	"errors"
 | |
| 
 | |
| 	"github.com/ooni/probe-cli/v3/internal/netxlite"
 | |
| )
 | |
| 
 | |
| // SafeErrWrapperBuilder contains a builder for ErrWrapper that
 | |
| // is safe, i.e., behaves correctly when the error is nil.
 | |
| type SafeErrWrapperBuilder struct {
 | |
| 	// Error is the error, if any
 | |
| 	Error error
 | |
| 
 | |
| 	// Classifier is the local error to string classifier. When there is no
 | |
| 	// configured classifier we will use the generic classifier.
 | |
| 	Classifier func(err error) string
 | |
| 
 | |
| 	// Operation is the operation that failed
 | |
| 	Operation string
 | |
| }
 | |
| 
 | |
| // MaybeBuild builds a new ErrWrapper, if b.Error is not nil, and returns
 | |
| // a nil error value, instead, if b.Error is nil.
 | |
| func (b SafeErrWrapperBuilder) MaybeBuild() (err error) {
 | |
| 	if b.Error != nil {
 | |
| 		classifier := b.Classifier
 | |
| 		if classifier == nil {
 | |
| 			classifier = netxlite.ClassifyGenericError
 | |
| 		}
 | |
| 		err = &netxlite.ErrWrapper{
 | |
| 			Failure:    classifier(b.Error),
 | |
| 			Operation:  toOperationString(b.Error, b.Operation),
 | |
| 			WrappedErr: b.Error,
 | |
| 		}
 | |
| 	}
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func toOperationString(err error, operation string) string {
 | |
| 	var errwrapper *netxlite.ErrWrapper
 | |
| 	if errors.As(err, &errwrapper) {
 | |
| 		// Basically, as explained in ErrWrapper docs, let's
 | |
| 		// keep the child major operation, if any.
 | |
| 		if errwrapper.Operation == netxlite.ConnectOperation {
 | |
| 			return errwrapper.Operation
 | |
| 		}
 | |
| 		if errwrapper.Operation == netxlite.HTTPRoundTripOperation {
 | |
| 			return errwrapper.Operation
 | |
| 		}
 | |
| 		if errwrapper.Operation == netxlite.ResolveOperation {
 | |
| 			return errwrapper.Operation
 | |
| 		}
 | |
| 		if errwrapper.Operation == netxlite.TLSHandshakeOperation {
 | |
| 			return errwrapper.Operation
 | |
| 		}
 | |
| 		if errwrapper.Operation == netxlite.QUICHandshakeOperation {
 | |
| 			return errwrapper.Operation
 | |
| 		}
 | |
| 		if errwrapper.Operation == "quic_handshake_start" {
 | |
| 			return netxlite.QUICHandshakeOperation
 | |
| 		}
 | |
| 		if errwrapper.Operation == "quic_handshake_done" {
 | |
| 			return netxlite.QUICHandshakeOperation
 | |
| 		}
 | |
| 		// FALLTHROUGH
 | |
| 	}
 | |
| 	return operation
 | |
| }
 |