github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/kit/httptransport/route_meta.go (about) 1 package httptransport 2 3 import ( 4 "reflect" 5 "regexp" 6 "strings" 7 8 "github.com/fatih/color" 9 "github.com/julienschmidt/httprouter" 10 11 "github.com/machinefi/w3bstream/pkg/depends/kit/httptransport/httpx" 12 "github.com/machinefi/w3bstream/pkg/depends/kit/kit" 13 ) 14 15 type MethodDescriber interface { 16 Method() string 17 } 18 19 type PathDescriber interface { 20 Path() string 21 } 22 23 type BasePathDescriber interface { 24 BasePath() string 25 } 26 27 var pkgHTTPx = reflect.TypeOf(httpx.MethodGet{}).PkgPath() 28 29 func NewOperatorFactoryWithRouteMeta(op kit.Operator, last bool) *OperatorFactoryWithRouteMeta { 30 f := kit.NewOperatorFactory(op, last) 31 32 m := &OperatorFactoryWithRouteMeta{OperatorFactory: f} 33 34 m.ID = m.Type.Name() 35 36 if with, ok := op.(MethodDescriber); ok { 37 m.Method = with.Method() 38 } 39 40 if m.Type.Kind() == reflect.Struct { 41 for i := 0; i < m.Type.NumField(); i++ { 42 ft := m.Type.Field(i) 43 if !ft.Anonymous || ft.Type.PkgPath() != pkgHTTPx || 44 !strings.HasPrefix(ft.Name, "Method") { 45 continue 46 } 47 // here can parse output operator 48 if path, ok := ft.Tag.Lookup("path"); ok { 49 vs := strings.Split(path, ",") 50 m.Path = vs[0] 51 52 if len(vs) > 0 { 53 for i := range vs { 54 switch vs[i] { 55 case "deprecated": 56 m.Deprecated = true 57 } 58 } 59 } 60 } 61 62 if basePath, ok := ft.Tag.Lookup("basePath"); ok { 63 m.BasePath = basePath 64 } 65 66 if summary, ok := ft.Tag.Lookup("summary"); ok { 67 m.Summary = summary 68 } 69 70 break 71 } 72 } 73 74 if with, ok := op.(BasePathDescriber); ok { 75 m.BasePath = with.BasePath() 76 } 77 78 if with, ok := m.Operator.(PathDescriber); ok { 79 m.Path = with.Path() 80 } 81 82 return m 83 } 84 85 type RouteMeta struct { 86 ID string // ID operator name 87 Method string // Method http method implement MethodDescriber 88 Path string // Path in tag `path` 89 BasePath string // BasePath base path 90 Summary string // Summary operator's desc 91 Deprecated bool 92 } 93 94 type OperatorFactoryWithRouteMeta struct { 95 *kit.OperatorFactory 96 RouteMeta 97 } 98 99 func NewHttpRouteMeta(route *kit.Route) *HttpRouteMeta { 100 metas := make([]*OperatorFactoryWithRouteMeta, len(route.Operators)) 101 102 for i := range route.Operators { 103 metas[i] = NewOperatorFactoryWithRouteMeta( 104 route.Operators[i], 105 i == len(route.Operators)-1, 106 ) 107 } 108 109 return &HttpRouteMeta{ 110 Route: route, 111 Metas: metas, 112 } 113 } 114 115 type HttpRouteMeta struct { 116 Route *kit.Route 117 Metas []*OperatorFactoryWithRouteMeta 118 } 119 120 func (hr *HttpRouteMeta) OperatorNames() string { 121 names := make([]string, 0) 122 123 for _, m := range hr.Metas { 124 if m.NoOutput { 125 continue 126 } 127 if m.IsLast { 128 names = append(names, color.MagentaString(m.String())) 129 } else { 130 names = append(names, color.CyanString(m.String())) 131 } 132 } 133 134 return strings.Join(names, " ") 135 } 136 137 func (hr *HttpRouteMeta) Key() string { 138 return regexpHttpRouterPath.ReplaceAllString(hr.Path(), "/{$1}") + " " + hr.OperatorNames() 139 } 140 141 func (hr *HttpRouteMeta) String() string { 142 method := hr.Method() 143 144 return methodColor(method)("%s %s", method[0:3], hr.Key()) 145 } 146 147 func (hr *HttpRouteMeta) Log() { 148 method := hr.Method() 149 150 last := hr.Metas[len(hr.Metas)-1] 151 152 firstLine := methodColor(method)( 153 "%s %s", method[0:3], 154 regexpHttpRouterPath.ReplaceAllString(hr.Path(), "/{$1}")) 155 156 if last.Deprecated { 157 firstLine = firstLine + " Deprecated" 158 } 159 160 if last.Summary != "" { 161 firstLine = firstLine + " " + last.Summary 162 } 163 164 outputln(firstLine) 165 outputln("\t%s", hr.OperatorNames()) 166 } 167 168 var regexpHttpRouterPath = regexp.MustCompile("/:([^/]+)") 169 170 func (hr *HttpRouteMeta) Method() string { 171 method := "" 172 for _, m := range hr.Metas { 173 if m.Method != "" { 174 method = m.Method 175 } 176 } 177 return method 178 } 179 180 func (hr *HttpRouteMeta) Path() string { 181 basePath := "/" 182 p := "" 183 184 for _, m := range hr.Metas { 185 if m.BasePath != "" { 186 basePath = m.BasePath 187 } 188 189 if m.Path != "" { 190 p += m.Path 191 } 192 } 193 194 return httprouter.CleanPath(basePath + p) 195 } 196 197 type MetaOperator struct { 198 kit.EmptyOperator 199 path string 200 basePath string 201 } 202 203 func BasePath(basePath string) *MetaOperator { return &MetaOperator{basePath: basePath} } 204 205 func Group(path string) *MetaOperator { return &MetaOperator{path: path} } 206 207 func (g *MetaOperator) Path() string { return g.path } 208 209 func (g *MetaOperator) BasePath() string { return g.basePath }