package app import ( "context" "fmt" "log" "net/url" "reflect" "git.loafle.net/loafer/di-go" appAnnotation "git.loafle.net/totopia/server/pkg/loafer/app/annotation" webAnnotation "git.loafle.net/totopia/server/pkg/loafer/web/annotation" "git.loafle.net/totopia/server/pkg/loafer/web/router" "github.com/valyala/fasthttp" "github.com/jackc/pgx/v4/pgxpool" ) type MethodMapping struct { Method string ParamKeys []string } func Run(t reflect.Type) error { pool, err := buildPgx(t) if nil != err { return fmt.Errorf("[%v]", err) } defer pool.Close() taServer := di.GetTypeAnnotation(t, appAnnotation.ServerAnnotationType) if nil == taServer { return fmt.Errorf("[%s] is not Server, use @app:Server", t.Elem().Name()) } aServer := taServer.(*appAnnotation.ServerAnnotation) log.Printf("%s %d", t.Elem().Name(), aServer.HTTPPort) restHandlers, err := di.GetInstancesByAnnotationType(webAnnotation.RestHandlerAnnotationType) if nil != err { return fmt.Errorf("[%v]", err) } r := router.New() for _, restHandler := range restHandlers { rha := parseRestHandler(restHandler) parseRequestMapping(rha, r, restHandler) } if err := fasthttp.ListenAndServe(fmt.Sprintf(":%d", aServer.HTTPPort), r.Handler); nil != err { return err } return nil } func buildPgx(t reflect.Type) (*pgxpool.Pool, error) { taPgx := di.GetTypeAnnotation(t, webAnnotation.PgxAnnotationType) if nil == taPgx { return nil, fmt.Errorf("[%s] is not Pgx, use @web:Pgx", t.Elem().Name()) } aPgx := taPgx.(*webAnnotation.PgxAnnotation) pgURL := &url.URL{ Scheme: "postgres", User: url.UserPassword(aPgx.User, aPgx.Password), Path: aPgx.Database, } q := pgURL.Query() if aPgx.SSLMode { q.Add("sslmode", "enable") } else { q.Add("sslmode", "disable") } pgURL.RawQuery = q.Encode() config, err := pgxpool.ParseConfig(pgURL.String()) if err != nil { return nil, fmt.Errorf("[%v]", err) } config.ConnConfig.Host = aPgx.Host config.ConnConfig.Port = aPgx.Port pool, err := pgxpool.ConnectConfig(context.Background(), config) if err != nil { return nil, fmt.Errorf("[%v]", err) } di.RegisterResource("dbConnPool", pool) return pool, nil } func parseRestHandler(restHandler interface{}) *webAnnotation.RestHandlerAnnotation { t := reflect.TypeOf(restHandler) ta := di.GetTypeAnnotation(t, webAnnotation.RestHandlerAnnotationType) if nil == ta { log.Printf("Service[%s] is not RESTService, use @RESTService", t.Elem().Name()) return nil } return ta.(*webAnnotation.RestHandlerAnnotation) } func parseRequestMapping(rha *webAnnotation.RestHandlerAnnotation, r *router.Router, restHandler interface{}) { t := reflect.TypeOf(restHandler) mas := di.GetMethodAnnotations(t, webAnnotation.RequestMappingAnnotationType) if nil == mas || 0 == len(mas) { return } mf := func(rh interface{}, mn string) fasthttp.RequestHandler { return func(ctx *fasthttp.RequestCtx) { reflect.ValueOf(rh).MethodByName(mn).Call([]reflect.Value{reflect.ValueOf(ctx)}) } } for methodName, v := range mas { ma := v.(*webAnnotation.RequestMappingAnnotation) entry := fmt.Sprintf("%s%s", rha.Entry, ma.Entry) log.Printf("methodName %s entry %s", methodName, entry) r.Handle(ma.Method, entry, mf(restHandler, methodName)) } }