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 }
// 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) }