// Invoke the given method, save headers/cookies to the response, and apply the // result. (e.g. render a template to the response) func (c *Controller) Invoke(appControllerPtr reflect.Value, method reflect.Value, methodArgs []reflect.Value) { // Handle panics. defer func() { if err := recover(); err != nil { handleInvocationPanic(c, err) } plugins.Finally(c) }() // Clean up from the request. defer func() { // Delete temp files. if c.Request.MultipartForm != nil { err := c.Request.MultipartForm.RemoveAll() if err != nil { WARN.Println("Error removing temporary files:", err) } } for _, tmpFile := range c.Params.tmpFiles { err := os.Remove(tmpFile.Name()) if err != nil { WARN.Println("Could not remove upload temp file:", err) } } }() // Run the plugins. plugins.BeforeRequest(c) if c.Result == nil { // Invoke the action. var resultValue reflect.Value if method.Type().IsVariadic() { resultValue = method.CallSlice(methodArgs)[0] } else { resultValue = method.Call(methodArgs)[0] } if resultValue.Kind() == reflect.Interface && !resultValue.IsNil() { c.Result = resultValue.Interface().(Result) } plugins.AfterRequest(c) if c.Result == nil { return } } // Apply the result, which generally results in the ResponseWriter getting written. c.Result.Apply(c.Request, c.Response) }
func (engine *Engine) GoFuncToJsFunc(gofunc reflect.Value) *FunctionTemplate { funcType := gofunc.Type() return engine.NewFunctionTemplate(func(callbackInfo FunctionCallbackInfo) { numIn := funcType.NumIn() numArgs := callbackInfo.Length() var out []reflect.Value if funcType.IsVariadic() { in := make([]reflect.Value, 1) in[0] = reflect.MakeSlice(funcType.In(0), numArgs, numArgs) for i := 0; i < numArgs; i++ { jsvalue := callbackInfo.Get(i) engine.SetJsValueToGo(in[0].Index(i), jsvalue) } out = gofunc.CallSlice(in) } else { in := make([]reflect.Value, numIn) for i := 0; i < len(in); i++ { jsvalue := callbackInfo.Get(i) in[i] = reflect.Indirect(reflect.New(funcType.In(i))) engine.SetJsValueToGo(in[i], jsvalue) } out = gofunc.Call(in) } if out == nil { callbackInfo.CurrentScope().ThrowException("argument number not match") return } switch { // when Go function returns only one value case len(out) == 1: callbackInfo.ReturnValue().Set(engine.GoValueToJsValue(out[0])) // when Go function returns multi-value, put them in a JavaScript array case len(out) > 1: jsResults := engine.NewArray(len(out)) jsResultsArray := jsResults.ToArray() for i := 0; i < len(out); i++ { jsResultsArray.SetElement(i, engine.GoValueToJsValue(out[i])) } callbackInfo.ReturnValue().Set(jsResults) } }, nil) }
func wrapperGen(l *Luna, impl reflect.Value) lua.LuaGoFunction { typ := impl.Type() params := make([]reflect.Value, typ.NumIn()) return func(L *lua.State) int { for i := range params { params[i] = reflect.New(typ.In(i)).Elem() } args := L.GetTop() if args < len(params) { panic(fmt.Sprintf("Args: %d, Params: %d", args, len(params))) } var varargs reflect.Value if typ.IsVariadic() { params[len(params)-1] = params[len(params)-1].Slice(0, 0) varargs = params[len(params)-1] } for i := 1; i <= args; i++ { if i >= len(params) && typ.IsVariadic() { val := reflect.New(varargs.Type().Elem()).Elem() l.set(val, i) varargs = reflect.Append(varargs, val) } else if i > len(params) { // ignore extra args break } else { if err := l.set(params[i-1], i); err != nil { panic(err) } } } var ret []reflect.Value if typ.IsVariadic() { params[len(params)-1] = varargs ret = impl.CallSlice(params) } else { ret = impl.Call(params) } for _, val := range ret { if l.pushBasicType(val.Interface()) { continue } if err := l.pushComplexType(val.Interface()); err != nil { panic(err) } } return len(ret) } }
func safeCall(obj reflect.Value, in []reflect.Value) (ok bool, out []reflect.Value, err error) { defer func() { if r := recover(); r != nil { ok = false err = fmt.Errorf("%v", r) } }() if obj.Type().IsVariadic() { out = obj.CallSlice(in) } else { out = obj.Call(in) } return true, out, nil }
func (s *Server) newHandlerFn(handler interface{}, f *reflect.Value, guards []GuarderFn) HandlerFn { return func(request *Request) (Reply, error) { input := []reflect.Value{reflect.ValueOf(handler)} for _, guard := range guards { value, errReply := guard(request) if errReply != nil { return errReply, nil } input = append(input, value) } if f.Type().NumIn() == 0 { input = []reflect.Value{} } else if !f.Type().In(0).AssignableTo(reflect.TypeOf(handler)) { input = input[1:] } var monitorString string if len(request.Arguments) > 0 { monitorString = fmt.Sprintf("%.6f [0 %s] \"%s\" \"%s\"", float64(time.Now().UTC().UnixNano())/1e9, request.RemoteAddress, request.Command, bytes.Join(request.Arguments, []byte{'"', ' ', '"'})) } else { monitorString = fmt.Sprintf("%.6f [0 %s] \"%s\"", float64(time.Now().UTC().UnixNano())/1e9, request.RemoteAddress, request.Command) } if s.MonitorLog { log.Printf("[Monitor] %s", monitorString) } var results []reflect.Value if f.Type().IsVariadic() { results = f.CallSlice(input) } else { results = f.Call(input) } if err := results[len(results)-1].Interface(); err != nil { return &ErrorReply{err.(error).Error()}, nil } if len(results) > 1 { return NewReply(s, request, results[0].Interface()) } return &StatusReply{"OK"}, nil } }
func createHandlerFunc(o interface{}, f *reflect.Value) (HandlerFunc, error) { t := f.Type() arg0Type := reflect.TypeOf((*interface{})(nil)).Elem() argsType := reflect.TypeOf([][]byte{}) if t.NumIn() != 3 || t.In(1) != arg0Type || t.In(2) != argsType { return nil, errors.Errorf("register with invalid func type = '%s'", t) } ret0Type := reflect.TypeOf((*Resp)(nil)).Elem() ret1Type := reflect.TypeOf((*error)(nil)).Elem() if t.NumOut() != 2 || t.Out(0) != ret0Type || t.Out(1) != ret1Type { return nil, errors.Errorf("register with invalid func type = '%s'", t) } return func(arg0 interface{}, args ...[]byte) (Resp, error) { var arg0Value reflect.Value if arg0 == nil { arg0Value = reflect.ValueOf((*interface{})(nil)) } else { arg0Value = reflect.ValueOf(arg0) } var input, output []reflect.Value input = []reflect.Value{reflect.ValueOf(o), arg0Value, reflect.ValueOf(args)} if t.IsVariadic() { output = f.CallSlice(input) } else { output = f.Call(input) } var ret0 Resp var ret1 error if i := output[0].Interface(); i != nil { ret0 = i.(Resp) } if i := output[1].Interface(); i != nil { ret1 = i.(error) } return ret0, ret1 }, nil }
func (this *Module) router(method, pattern string, controllerOrhandler []interface{}) { this.Mutex.Lock() defer func() { recover() this.Mutex.Unlock() }() if pattern[0] != '/' { pattern = "/" + SnakeString(pattern) } else { pattern = "/" + SnakeString(pattern[1:]) } pattern = strings.Replace(pattern, "/?", "?", -1) pattern = strings.Trim(pattern, "?") pattern = strings.TrimSuffix(pattern, "/") a := re.FindStringSubmatch(pattern) if len(a) < 3 { log.Panicln(`[ERROR] 配置路由规则: 匹配规则 "` + pattern + `" 不正确`) } var ( hfs = make([]HandlerFunc, len(controllerOrhandler)) countController int cName string callfunc = CamelString(strings.TrimPrefix(a[1], "/")) ) for i, v := range controllerOrhandler { c, ok := v.(Controller) if ok { cName, callfunc, hfs[i] = this.newHandler(method, callfunc, c) countController++ continue } h, ok := v.(HandlerFunc) if ok { hfs[i] = h continue } log.Panicln(`[ERROR] 配置路由规则: "` + this.RouterGroup.BasePath() + method + `" 指定了类型错误的操作`) } if countController != 1 { log.Panicln(`[ERROR] 配置路由规则: "` + this.RouterGroup.BasePath() + method + `" 须且仅须设置1个控制器`) } { callMethod := reflect.ValueOf(this.RouterGroup).MethodByName(method) // 当为"home"模块时,添加注册根路由 var defaultCallMethod reflect.Value if this.RouterGroup.BasePath() == "/home" { defaultCallMethod = reflect.ValueOf(ThinkGo).MethodByName(method) } hfsv := reflect.ValueOf(hfs) if callfunc == "index" && a[2] != "/" { // 允许省略index p := path.Join(cName, pattern[len(a[1]):]) p = strings.Replace(p, "/?", "?", -1) param := []reflect.Value{reflect.ValueOf(p), hfsv} callMethod.CallSlice(param) if defaultCallMethod != (reflect.Value{}) { defaultCallMethod.CallSlice(param) } if cName == "index" { param = []reflect.Value{reflect.ValueOf(pattern[len(a[1]):]), hfsv} callMethod.CallSlice(param) if defaultCallMethod != (reflect.Value{}) { defaultCallMethod.CallSlice(param) } } } param := []reflect.Value{reflect.ValueOf(path.Join(cName, pattern)), hfsv} callMethod.CallSlice(param) if defaultCallMethod != (reflect.Value{}) { defaultCallMethod.CallSlice(param) } } }
func (srv *Server) handlerFn(autoHandler interface{}, f *reflect.Value, checkers []CheckerFn) (HandlerFn, error) { return func(request *Request) (ReplyWriter, error) { input := []reflect.Value{reflect.ValueOf(autoHandler)} for _, checker := range checkers { value, reply := checker(request) if reply != nil { return reply, nil } input = append(input, value) } var monitorString string if len(request.Args) > 0 { monitorString = fmt.Sprintf("%.6f [0 %s] \"%s\" \"%s\"", float64(time.Now().UTC().UnixNano())/1e9, request.Host, request.Name, bytes.Join(request.Args, []byte{'"', ' ', '"'})) } else { monitorString = fmt.Sprintf("%.6f [0 %s] \"%s\"", float64(time.Now().UTC().UnixNano())/1e9, request.Host, request.Name) } for _, c := range srv.MonitorChans { select { case c <- monitorString: default: } } Debugf("%s (connected monitors: %d)\n", monitorString, len(srv.MonitorChans)) var result []reflect.Value // If we don't have any input, it means we are dealing with a function. // Then remove the first parameter (object instance) if f.Type().NumIn() == 0 { input = []reflect.Value{} } else if f.Type().In(0).AssignableTo(reflect.TypeOf(autoHandler)) == false { // If we have at least one input, we check if the first one is an instance of our object // If it is, then remove it from the input list. input = input[1:] } if f.Type().IsVariadic() { result = f.CallSlice(input) } else { result = f.Call(input) } var ret interface{} if ierr := result[len(result)-1].Interface(); ierr != nil { // Last return value is an error, wrap it to redis error err := ierr.(error) // convert to redis error reply return NewError(err.Error()), nil } if len(result) > 1 { ret = result[0].Interface() return srv.createReply(request, ret) } return &StatusReply{Code: "OK"}, nil }, nil }
// call fn, remove its args from the stack and push the result func (s *State) call(fn reflect.Value, ftyp reflect.Type, numIn int, isVariadic bool, name string, args int, traits FuncTrait, fp fastPath) error { pos := len(s.stack) - args in := s.stack[pos : pos+args] last := numIn if isVariadic { last-- if args < last { // Show the number of passed arguments without the context // in the error, otherwise it can be confusing for the user. tn := traits.nTraitArgs() last -= tn args -= tn return fmt.Errorf("function %q requires at least %d arguments, %d given", funcDebugName(name, fn), last, args) } } else { if args != numIn { // See comment after the previous args < last tn := traits.nTraitArgs() last -= tn args -= tn return fmt.Errorf("function %q requires exactly %d arguments, %d given", funcDebugName(name, fn), numIn, args) } } // arguments are in reverse order for ii := 0; ii < len(in)/2; ii++ { in[ii], in[len(in)-1-ii] = in[len(in)-1-ii], in[ii] } var lastType reflect.Type for ii, v := range in { var ityp reflect.Type if ii < last { ityp = ftyp.In(ii) } else { ityp = ftyp.In(last).Elem() lastType = ityp } if !v.IsValid() { in[ii] = reflect.Zero(ityp) continue } vtyp := v.Type() if !vtyp.AssignableTo(ityp) { k := vtyp.Kind() if (k == reflect.Ptr || k == reflect.Interface) && !v.IsNil() && vtyp.Elem().AssignableTo(ityp) { in[ii] = v.Elem() continue } if reflect.PtrTo(vtyp).AssignableTo(ityp) && v.CanAddr() { in[ii] = v.Addr() continue } if ii == 0 && traits.HasTrait(FuncTraitContext) { return fmt.Errorf("context function %q requires a context of type %s, not %s", name, ityp, vtyp) } return fmt.Errorf("can't call %q with %s as argument %d, need %s", name, vtyp, ii+1, ityp) } } var res []reflect.Value if isVariadic { // empty the scratch here, so it's only pointless // the first time. the alternative would be emptying it // after the call and in reset(), because CallSlice can end // up calling a function which panics. that would cause // a lot of unrequired emptys because templates don't // necessarily use the scratch. s.scratch = s.scratch[:0] for _, v := range in[last:] { s.scratch = append(s.scratch, v.Interface()) } if fp != nil { if err := fp(in, s.scratch, s.resPtr); err != nil { return fmt.Errorf("%q returned an error: %s", name, err) } res = s.res } else { if len(in) <= last { // no varargs provided by the call, but // CallSlice requires an empty slice at // the end. in = append(in, reflect.Value{}) } if lastType == emptyType { in[last] = reflect.ValueOf(s.scratch) } else { lastSlice := reflect.MakeSlice(ftyp.In(last), len(s.scratch), len(s.scratch)) for ii, v := range s.scratch { lastSlice.Index(ii).Set(reflect.ValueOf(v)) } in[last] = lastSlice } in = in[:last+1] res = fn.CallSlice(in) } } else { if fp != nil { if err := fp(in, nil, s.resPtr); err != nil { return fmt.Errorf("%q returned an error: %s", name, err) } res = s.res } else { res = fn.Call(in) } } if len(res) == 2 && !res[1].IsNil() { return fmt.Errorf("%q returned an error: %s", name, res[1].Interface()) } s.stack = append(s.stack[:pos], stackable(res[0])) return nil }