github.com/profzone/eden-framework@v1.0.10/pkg/courier/transport_http/http_route_meta.go (about)

     1  package transport_http
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/profzone/eden-framework/pkg/courier"
     6  	"github.com/profzone/eden-framework/pkg/courier/httpx"
     7  	"net/http"
     8  	"reflect"
     9  	"regexp"
    10  	"strings"
    11  
    12  	"github.com/fatih/color"
    13  	"github.com/julienschmidt/httprouter"
    14  )
    15  
    16  type MethodDescriber interface {
    17  	Method() string
    18  }
    19  
    20  type PathDescriber interface {
    21  	Path() string
    22  }
    23  
    24  type BasePathDescriber interface {
    25  	BasePath() string
    26  }
    27  
    28  var pkgPathHttpx = reflect.TypeOf(httpx.MethodGet{}).PkgPath()
    29  
    30  func NewOperatorFactoryWithRouteMeta(op courier.IOperator, last bool) *OperatorFactoryWithRouteMeta {
    31  	f := courier.NewOperatorFactory(op, last)
    32  
    33  	m := &OperatorFactoryWithRouteMeta{
    34  		OperatorFactory: f,
    35  	}
    36  
    37  	m.ID = m.Type.Name()
    38  
    39  	if methodDescriber, ok := op.(MethodDescriber); ok {
    40  		m.Method = methodDescriber.Method()
    41  	}
    42  
    43  	if m.Type.Kind() == reflect.Struct {
    44  		structType := m.Type
    45  
    46  		for i := 0; i < structType.NumField(); i++ {
    47  			f := structType.Field(i)
    48  			if f.Anonymous && f.Type.PkgPath() == pkgPathHttpx && strings.HasPrefix(f.Name, "Method") {
    49  				if path, ok := f.Tag.Lookup("path"); ok {
    50  					vs := strings.Split(path, ",")
    51  					m.Path = vs[0]
    52  
    53  					if len(vs) > 0 {
    54  						for i := range vs {
    55  							switch vs[i] {
    56  							case "deprecated":
    57  								m.Deprecated = true
    58  								break
    59  							}
    60  						}
    61  					}
    62  				}
    63  
    64  				if basePath, ok := f.Tag.Lookup("basePath"); ok {
    65  					m.BasePath = basePath
    66  				}
    67  
    68  				if summary, ok := f.Tag.Lookup("summary"); ok {
    69  					m.Summary = summary
    70  				}
    71  
    72  				break
    73  			}
    74  		}
    75  	}
    76  
    77  	if basePathDescriber, ok := op.(BasePathDescriber); ok {
    78  		m.BasePath = basePathDescriber.BasePath()
    79  	}
    80  
    81  	if pathDescriber, ok := m.Operator.(PathDescriber); ok {
    82  		m.Path = pathDescriber.Path()
    83  	}
    84  
    85  	return m
    86  }
    87  
    88  type RouteMeta struct {
    89  	ID         string
    90  	Method     string
    91  	Path       string
    92  	BasePath   string
    93  	Summary    string
    94  	Deprecated bool
    95  }
    96  
    97  type OperatorFactoryWithRouteMeta struct {
    98  	*courier.OperatorFactory
    99  	RouteMeta
   100  }
   101  
   102  func NewHttpRouteMeta(route *courier.Route) *HttpRouteMeta {
   103  	operatorFactoryWithRouteMetas := make([]*OperatorFactoryWithRouteMeta, len(route.Operators))
   104  
   105  	for i := range route.Operators {
   106  		operatorFactoryWithRouteMetas[i] = NewOperatorFactoryWithRouteMeta(route.Operators[i], i == len(route.Operators)-1)
   107  	}
   108  
   109  	return &HttpRouteMeta{
   110  		Route:                         route,
   111  		OperatorFactoryWithRouteMetas: operatorFactoryWithRouteMetas,
   112  	}
   113  }
   114  
   115  type HttpRouteMeta struct {
   116  	Route                         *courier.Route
   117  	OperatorFactoryWithRouteMetas []*OperatorFactoryWithRouteMeta
   118  }
   119  
   120  func (route *HttpRouteMeta) OperatorNames() string {
   121  	operatorTypeNames := make([]string, 0)
   122  
   123  	for _, opFactory := range route.OperatorFactoryWithRouteMetas {
   124  		if opFactory.NoOutput {
   125  			continue
   126  		}
   127  
   128  		if opFactory.IsLast {
   129  			operatorTypeNames = append(operatorTypeNames, color.MagentaString(opFactory.String()))
   130  		} else {
   131  			operatorTypeNames = append(operatorTypeNames, color.CyanString(opFactory.String()))
   132  		}
   133  	}
   134  
   135  	return strings.Join(operatorTypeNames, " ")
   136  }
   137  
   138  func (route *HttpRouteMeta) Key() string {
   139  	return reHttpRouterPath.ReplaceAllString(route.Path(), "/{$1}") + " " + route.OperatorNames()
   140  }
   141  
   142  func (route *HttpRouteMeta) String() string {
   143  	method := route.Method()
   144  
   145  	return methodColor(method)("%s %s", method[0:3], route.Key())
   146  }
   147  
   148  func (route *HttpRouteMeta) Log() {
   149  	method := route.Method()
   150  
   151  	last := route.OperatorFactoryWithRouteMetas[len(route.OperatorFactoryWithRouteMetas)-1]
   152  
   153  	firstLine := methodColor(method)("%s %s", method[0:3], reHttpRouterPath.ReplaceAllString(route.Path(), "/{$1}"))
   154  
   155  	if last.Deprecated {
   156  		firstLine = firstLine + " Deprecated"
   157  	}
   158  
   159  	if last.Summary != "" {
   160  		firstLine = firstLine + " " + last.Summary
   161  	}
   162  
   163  	fmt.Println("[Courier] ", firstLine)
   164  	fmt.Println("[Courier] ", "\t", route.OperatorNames())
   165  }
   166  
   167  var reHttpRouterPath = regexp.MustCompile("/:([^/]+)")
   168  
   169  func methodColor(method string) func(f string, args ...interface{}) string {
   170  	switch method {
   171  	case http.MethodGet:
   172  		return color.BlueString
   173  	case http.MethodPost:
   174  		return color.GreenString
   175  	case http.MethodPut:
   176  		return color.YellowString
   177  	case http.MethodDelete:
   178  		return color.RedString
   179  	default:
   180  		return color.WhiteString
   181  	}
   182  }
   183  
   184  func (route *HttpRouteMeta) Method() string {
   185  	method := ""
   186  	for _, m := range route.OperatorFactoryWithRouteMetas {
   187  		if m.Method != "" {
   188  			method = m.Method
   189  		}
   190  	}
   191  	return method
   192  }
   193  
   194  func (route *HttpRouteMeta) Path() string {
   195  	basePath := "/"
   196  	p := ""
   197  
   198  	for _, m := range route.OperatorFactoryWithRouteMetas {
   199  		if m.BasePath != "" {
   200  			basePath = m.BasePath
   201  		}
   202  
   203  		if m.Path != "" {
   204  			p += m.Path
   205  		}
   206  	}
   207  
   208  	return httprouter.CleanPath(basePath + p)
   209  }
   210  
   211  func BasePath(basePath string) *MetaOperator {
   212  	return &MetaOperator{
   213  		basePath: basePath,
   214  	}
   215  }
   216  
   217  func Group(path string) *MetaOperator {
   218  	return &MetaOperator{path: path}
   219  }
   220  
   221  type MetaOperator struct {
   222  	courier.EmptyOperator
   223  	path     string
   224  	basePath string
   225  }
   226  
   227  func (g *MetaOperator) Path() string {
   228  	return g.path
   229  }
   230  
   231  func (g *MetaOperator) BasePath() string {
   232  	return g.basePath
   233  }