github.com/sohaha/zlsgo@v1.7.13-0.20240501141223-10dd1a906f76/znet/bind_router.go (about) 1 package znet 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 8 "github.com/sohaha/zlsgo/zreflect" 9 "github.com/sohaha/zlsgo/zstring" 10 "github.com/sohaha/zlsgo/zutil" 11 ) 12 13 // BindStruct Bind Struct 14 func (e *Engine) BindStruct(prefix string, s interface{}, handle ...Handler) error { 15 g := e.Group(prefix) 16 if len(handle) > 0 { 17 for _, v := range handle { 18 g.Use(v) 19 } 20 } 21 of := reflect.ValueOf(s) 22 if !of.IsValid() { 23 return nil 24 } 25 initFn := of.MethodByName("Init") 26 if initFn.IsValid() { 27 before, ok := initFn.Interface().(func(e *Engine)) 28 if ok { 29 before(g) 30 } else { 31 if before, ok := initFn.Interface().(func(e *Engine) error); !ok { 32 return fmt.Errorf("func: [%s] is not an effective routing method", "Init") 33 } else { 34 if err := before(g); err != nil { 35 return err 36 } 37 } 38 } 39 40 } 41 typeOf := reflect.Indirect(of).Type() 42 return zutil.TryCatch(func() error { 43 return zreflect.ForEachMethod(of, func(i int, m reflect.Method, value reflect.Value) error { 44 if m.Name == "Init" { 45 return nil 46 } 47 path, method, key := "", "", "" 48 methods := `ANY|GET|POST|PUT|DELETE|PATCH|HEAD|OPTIONS` 49 regex := `^(?i)(` + methods + `)(.*)$` 50 info, err := zstring.RegexExtract(regex, m.Name) 51 infoLen := len(info) 52 if err != nil || infoLen != 3 { 53 indexs := zstring.RegexFind(`(?i)(`+methods+`)`, m.Name, 1) 54 if len(indexs) == 0 { 55 if e.IsDebug() && m.Name != "Init" { 56 e.Log.Warnf("matching rule error: %s%s\n", m.Name, m.Func.String()) 57 } 58 return nil 59 } 60 61 index := indexs[0] 62 method = strings.ToUpper(m.Name[index[0]:index[1]]) 63 path = m.Name[index[1]:] 64 key = strings.ToLower(m.Name[:index[0]]) 65 } else { 66 path = info[2] 67 method = strings.ToUpper(info[1]) 68 } 69 70 fn := value.Interface() 71 handleName := strings.Join([]string{typeOf.PkgPath(), typeOf.Name(), m.Name}, ".") 72 if e.BindStructCase != nil { 73 path = e.BindStructCase(path) 74 } else if e.BindStructDelimiter != "" { 75 path = zstring.CamelCaseToSnakeCase(path, e.BindStructDelimiter) 76 } 77 if path == "" { 78 path = "/" 79 } 80 if key != "" { 81 if strings.HasSuffix(path, "/") { 82 path += ":" + key 83 } else { 84 path += "/:" + key 85 } 86 } else if path != "/" && e.BindStructSuffix != "" { 87 path = path + e.BindStructSuffix 88 } 89 if path == "/" { 90 path = "" 91 } 92 93 var ( 94 p string 95 l int 96 ok bool 97 ) 98 99 if method == "ANY" { 100 p, l, ok = g.handleAny(path, Utils.ParseHandlerFunc(fn), nil, nil) 101 } else { 102 p, l, ok = g.addHandle(method, path, Utils.ParseHandlerFunc(fn), nil, nil) 103 } 104 105 if ok && e.IsDebug() { 106 f := fmt.Sprintf("%%s %%-40s -> %s (%d handlers)", handleName, l) 107 if e.webMode == testCode { 108 f = "%s %-40s" 109 } 110 e.Log.Debug(routeLog(e.Log, f, method, p)) 111 } 112 return nil 113 }) 114 }) 115 }