9 "github.com/gin-gonic/gin"
10 "github.com/jinzhu/gorm"
12 "github.com/vapor/errors"
13 "github.com/vapor/toolbar/federation/config"
22 func NewServer(db *gorm.DB, cfg *config.Config) *Server {
27 if cfg.API.IsReleaseMode {
28 gin.SetMode(gin.ReleaseMode)
34 func (server *Server) setupRouter() {
36 r.Use(server.middleware())
38 v1 := r.Group("/api/v1")
39 v1.POST("/federation/list-crosschain-txs", handlerMiddleware(server.ListCrosschainTxs))
40 v1.GET("/federation/list-chains", handlerMiddleware(server.ListChains))
45 func (s *Server) Run() {
49 func (s *Server) middleware() gin.HandlerFunc {
50 return func(c *gin.Context) {
51 // add Access-Control-Allow-Origin
52 c.Header("Access-Control-Allow-Origin", "*")
53 c.Header("Access-Control-Allow-Headers", "Content-Type")
54 c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
55 if c.Request.Method == "OPTIONS" {
56 c.AbortWithStatus(http.StatusOK)
65 type handlerFun interface{}
67 func handlerMiddleware(handleFunc interface{}) func(*gin.Context) {
68 if err := validateFuncType(handleFunc); err != nil {
72 return func(context *gin.Context) {
73 handleRequest(context, handleFunc)
77 func validateFuncType(fun handlerFun) error {
78 ft := reflect.TypeOf(fun)
79 if ft.Kind() != reflect.Func || ft.IsVariadic() {
80 return errors.New("need nonvariadic func in " + ft.String())
83 if ft.NumIn() < 1 || ft.NumIn() > 3 {
84 return errors.New("need one or two or three parameters in " + ft.String())
87 if ft.In(0) != contextType {
88 return errors.New("the first parameter must point of context in " + ft.String())
91 if ft.NumIn() == 2 && ft.In(1).Kind() != reflect.Ptr {
92 return errors.New("the second parameter must point in " + ft.String())
95 if ft.NumIn() == 3 && ft.In(2) != paginationQueryType {
96 return errors.New("the third parameter of pagination must point of paginationQuery in " + ft.String())
99 if ft.NumOut() < 1 || ft.NumOut() > 2 {
100 return errors.New("the size of return value must one or two in " + ft.String())
103 // if has pagination, the first return value must slice or array
104 if ft.NumIn() == 3 && ft.Out(0).Kind() != reflect.Slice && ft.Out(0).Kind() != reflect.Array {
105 return errors.New("the first return value of pagination must slice of array in " + ft.String())
108 if !ft.Out(ft.NumOut() - 1).Implements(errorType) {
109 return errors.New("the last return value must error in " + ft.String())
114 // handleRequest get a handler function to process the request by request url
115 func handleRequest(context *gin.Context, fun handlerFun) {
116 args, err := buildHandleFuncArgs(fun, context)
118 respondErrorResp(context, err)
122 result := callHandleFunc(fun, args...)
123 if err := result[len(result)-1]; err != nil {
124 respondErrorResp(context, err.(error))
128 if exist := processPaginationIfPresent(fun, args, result, context); exist {
132 if len(result) == 1 {
133 respondSuccessResp(context, nil)
137 respondSuccessResp(context, result[0])
140 func buildHandleFuncArgs(fun handlerFun, context *gin.Context) ([]interface{}, error) {
141 args := []interface{}{context}
143 req, err := createHandleReqArg(fun, context)
145 return nil, errors.Wrap(err, "createHandleReqArg")
148 if err := checkDisplayOrder(req); err != nil {
153 args = append(args, req)
156 ft := reflect.TypeOf(fun)
158 // no pagination exists
163 query, err := parsePagination(context)
165 return nil, errors.Wrap(err, "ParsePagination")
168 args = append(args, query)
172 func createHandleReqArg(fun handlerFun, context *gin.Context) (interface{}, error) {
173 ft := reflect.TypeOf(fun)
177 argType := ft.In(1).Elem()
179 reqArg := reflect.New(argType).Interface()
180 if err := context.ShouldBindJSON(reqArg); err != nil {
181 return nil, errors.Wrap(err, "bind reqArg")
184 b, err := json.Marshal(reqArg)
186 return nil, errors.Wrap(err, "json marshal")
189 context.Set(reqBodyLabel, string(b))
194 func checkDisplayOrder(req interface{}) error {
199 reqType := reflect.TypeOf(req).Elem()
200 reqVal := reflect.ValueOf(req).Elem()
202 for i := 0; i < reqType.NumField(); i++ {
203 field := reqType.Field(i)
204 if field.Type != reflect.TypeOf(Display{}) {
207 display := reqVal.Field(i).Interface().(Display)
209 order := strings.Trim(display.Sorter.Order, "")
210 if order != "desc" && order != "asc" {
211 reqVal.Field(i).Set(reflect.ValueOf(Display{Filter: display.Filter, Sorter: Sorter{By: display.Sorter.By, Order: "desc"}}))
217 func callHandleFunc(fun handlerFun, args ...interface{}) []interface{} {
218 fv := reflect.ValueOf(fun)
220 params := make([]reflect.Value, len(args))
221 for i, arg := range args {
222 params[i] = reflect.ValueOf(arg)
225 rs := fv.Call(params)
226 result := make([]interface{}, len(rs))
227 for i, r := range rs {
228 result[i] = r.Interface()