Example #1
0
// 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)
}
Example #2
0
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)
}
Example #3
0
File: util.go Project: breml/luna
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)
	}
}
Example #4
0
File: lua.go Project: hxyxj/goinfi
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
}
Example #5
0
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
	}
}
Example #6
0
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
}
Example #7
0
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)
		}
	}
}
Example #8
0
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
}
Example #9
0
// 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
}