func invokeByName(obj interface{}, name string, in ...reflect.Value) []reflect.Value { ov := reflect.NewValue(obj) ot := ov.Type() var fn *reflect.FuncValue = nil for i := 0; i < ot.NumMethod(); i++ { if ot.Method(i).Name == name { fn = ot.Method(i).Func break } } if fn == nil { return []reflect.Value{reflect.NewValue(nil)} } params := make([]reflect.Value, len(in)+1) params[0] = ov for i := 1; i < len(params); i++ { params[i] = in[i-1] } return fn.Call(params) }
//Calls a function with recover block func (s *Server) safelyCall(function *reflect.FuncValue, args []reflect.Value) (resp []reflect.Value, e interface{}) { defer func() { if err := recover(); err != nil { if !s.Config.RecoverPanic { // go back to panic panic(err) } else { e = err resp = nil s.Logger.Println("Handler crashed with error", err) for i := 1; ; i += 1 { _, file, line, ok := runtime.Caller(i) if !ok { break } s.Logger.Println(file, line) } } } }() return function.Call(args), nil }
func newThread(route []interface{}) *Thread { if len(route) == 0 { return nil } first := reflect.NewValue(route[0]) args := make([]reflect.Value, 0, 8) canStop := true ok := false var fv *reflect.FuncValue switch first.(type) { case *reflect.PtrValue: { if len(route) < 2 { return nil } if str, typeok := route[1].(string); typeok { fv = getMemFunc(first.(*reflect.PtrValue), str) typ := fv.Type().(*reflect.FuncType) needArgs := typ.NumIn() actualArgs := len(route) - 1 if needArgs == actualArgs { ok = true canStop = false } else if needArgs == actualArgs+1 { canStop = true ok = checkLastArg(typ) } if ok { args = append(args, first) for _, i := range route[2:] { args = append(args, reflect.NewValue(i)) } } } } case *reflect.FuncValue: { fv = first.(*reflect.FuncValue) typ := fv.Type().(*reflect.FuncType) needArgs := typ.NumIn() actualArgs := len(route) - 1 if needArgs == actualArgs { ok = true canStop = false } else if needArgs == actualArgs+1 { canStop = true ok = checkLastArg(typ) } if ok { for _, i := range route[1:] { args = append(args, reflect.NewValue(i)) } } } } if ok { t := new(Thread) t.fv = fv t.canStop = canStop t.args = args return t } return nil }
// tryOneFunction is the common code for tryMethod and tryFunction. func tryOneFunction(pkg, firstArg, name string, typ *reflect.FuncType, rfn *reflect.FuncValue, args []interface{}) { // Any results? if typ.NumOut() == 0 { return // Nothing to do. } // Right number of arguments + results? if typ.NumIn()+typ.NumOut() != len(args) { return } // Right argument and result types? for i, a := range args { if i < typ.NumIn() { if !compatible(a, typ.In(i)) { return } } else { if !compatible(a, typ.Out(i-typ.NumIn())) { return } } } // Build the call args. argsVal := make([]reflect.Value, typ.NumIn()+typ.NumOut()) for i, a := range args { argsVal[i] = reflect.NewValue(a) } // Call the function and see if the results are as expected. resultVal := rfn.Call(argsVal[:typ.NumIn()]) for i, v := range resultVal { if !reflect.DeepEqual(v.Interface(), args[i+typ.NumIn()]) { return } } // Present the result including a godoc command to get more information. firstIndex := 0 if firstArg != "" { fmt.Fprintf(output, "%s.%s(", firstArg, name) firstIndex = 1 } else { fmt.Fprintf(output, "%s.%s(", pkg, name) } for i := firstIndex; i < typ.NumIn(); i++ { if i > firstIndex { fmt.Fprint(output, ", ") } fmt.Fprintf(output, "%#v", args[i]) } fmt.Fprint(output, ") = ") if typ.NumOut() > 1 { fmt.Fprint(output, "(") } for i := 0; i < typ.NumOut(); i++ { if i > 0 { fmt.Fprint(output, ", ") } fmt.Fprintf(output, "%#v", resultVal[i].Interface()) } if typ.NumOut() > 1 { fmt.Fprint(output, ")") } fmt.Fprintf(output, " // godoc %s %s\n", pkg, name) }
func (c *C) logArgPanic(funcValue *reflect.FuncValue, expectedType string) { c.logf("... Panic: %s argument should be %s", niceFuncName(funcValue.Get()), expectedType) }