github.com/profzone/eden-framework@v1.0.10/internal/generator/scanner/status_error_scanner.go (about)

     1  package scanner
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/profzone/eden-framework/pkg/courier/status_error"
     6  	"github.com/profzone/eden-framework/pkg/packagex"
     7  	"github.com/profzone/eden-framework/pkg/reflectx"
     8  	"go/ast"
     9  	"go/types"
    10  	"sort"
    11  	"strconv"
    12  	"strings"
    13  )
    14  
    15  func NewStatusErrorScanner(pkg *packagex.Package) *StatusErrorScanner {
    16  	return &StatusErrorScanner{
    17  		pkg: pkg,
    18  	}
    19  }
    20  
    21  type StatusErrorScanner struct {
    22  	pkg          *packagex.Package
    23  	StatusErrors map[*types.TypeName][]*status_error.StatusError
    24  }
    25  
    26  func sortedStatusErrList(list []*status_error.StatusError) []*status_error.StatusError {
    27  	sort.Slice(list, func(i, j int) bool {
    28  		return list[i].Code < list[j].Code
    29  	})
    30  	return list
    31  }
    32  
    33  func (scanner *StatusErrorScanner) StatusError(typeName *types.TypeName) []*status_error.StatusError {
    34  	if typeName == nil {
    35  		return nil
    36  	}
    37  
    38  	if statusErrs, ok := scanner.StatusErrors[typeName]; ok {
    39  		return sortedStatusErrList(statusErrs)
    40  	}
    41  
    42  	if !strings.Contains(typeName.Type().Underlying().String(), "int") {
    43  		panic(fmt.Errorf("status error type underlying must be an int or uint, but got %s", typeName.String()))
    44  	}
    45  
    46  	pkgInfo := scanner.pkg.Pkg(typeName.Pkg().Path())
    47  	if pkgInfo == nil {
    48  		return nil
    49  	}
    50  
    51  	var serviceCode int64 = 0
    52  
    53  	method, ok := reflectx.FromTType(typeName.Type()).MethodByName("ServiceCode")
    54  	if ok {
    55  		results, n := scanner.pkg.FuncResultsOf(method.(*reflectx.TMethod).Func)
    56  		if n == 1 {
    57  			ret := results[0][0]
    58  			if ret.IsValue() {
    59  				if i, err := strconv.ParseInt(ret.Value.String(), 10, 64); err == nil {
    60  					serviceCode = i
    61  				}
    62  			}
    63  		}
    64  	}
    65  
    66  	for ident, def := range pkgInfo.TypesInfo.Defs {
    67  		typeConst, ok := def.(*types.Const)
    68  		if !ok {
    69  			continue
    70  		}
    71  		if typeConst.Type() != typeName.Type() {
    72  			continue
    73  		}
    74  
    75  		key := typeConst.Name()
    76  		code, _ := strconv.ParseInt(typeConst.Val().String(), 10, 64)
    77  
    78  		msg, canBeTalkError := ParseStatusErrMsg(ident.Obj.Decl.(*ast.ValueSpec).Doc.Text())
    79  
    80  		scanner.addStatusError(typeName, key, code+serviceCode, msg, canBeTalkError)
    81  	}
    82  
    83  	return sortedStatusErrList(scanner.StatusErrors[typeName])
    84  }
    85  
    86  func ParseStatusErrMsg(s string) (string, bool) {
    87  	firstLine := strings.Split(strings.TrimSpace(s), "\n")[0]
    88  
    89  	prefix := "@errTalk "
    90  	if strings.HasPrefix(firstLine, prefix) {
    91  		return firstLine[len(prefix):], true
    92  	}
    93  	return firstLine, false
    94  }
    95  
    96  func (scanner *StatusErrorScanner) addStatusError(
    97  	typeName *types.TypeName,
    98  	key string, code int64, msg string, canBeTalkError bool,
    99  ) {
   100  	if scanner.StatusErrors == nil {
   101  		scanner.StatusErrors = map[*types.TypeName][]*status_error.StatusError{}
   102  	}
   103  
   104  	statusErr := status_error.NewStatusError(key, code, msg)
   105  	if canBeTalkError {
   106  		statusErr = statusErr.WithErrTalk()
   107  	}
   108  	scanner.StatusErrors[typeName] = append(scanner.StatusErrors[typeName], statusErr)
   109  }