Skip to content

High performance secure GRPC/ORM/NODE framework

License

Notifications You must be signed in to change notification settings

godaddy-x/freego

Repository files navigation

freego

High performance secure GRPC/ORM/NODE framework

1. Create simple HTTP/NODE demo

type MyWebNode struct {
	node.HttpNode
}

func (self *MyWebNode) pubkey(ctx *node.Context) error {
	return self.Text(ctx, "hello world!!!")
}

func NewHTTP() *MyWebNode {
	var my = &MyWebNode{}
	my.AddJwtConfig(jwt.JwtConfig{
		TokenTyp: jwt.JWT,
		TokenAlg: jwt.HS256,
		TokenKey: "123456" + utils.CreateLocalSecretKey(12, 45, 23, 60, 58, 30),
		TokenExp: jwt.TWO_WEEK,
	})
	my.AddCacheAware(func(ds ...string) (cache.Cache, error) {
		return local, nil
	})
	return my
}

func main()  {
	my := NewHTTP()
	my.EnableECC(true) // use ecc, default rsa
	my.GET("/pubkey", my.pubkey, &node.RouterConfig{Guest: true})
	my.StartServer(":8090")
}

2. Create plugin filter chain

You can implement any pre and post operations, and configure MatchPattern parameter to apply the specified method

// default filters
var filterMap = map[string]*FilterObject{
	GatewayRateLimiterFilterName: {Name: GatewayRateLimiterFilterName, Order: -100, Filter: &GatewayRateLimiterFilter{}},
	ParameterFilterName:          {Name: ParameterFilterName, Order: -90, Filter: &ParameterFilter{}},
	SessionFilterName:            {Name: SessionFilterName, Order: -80, Filter: &SessionFilter{}},
	UserRateLimiterFilterName:    {Name: UserRateLimiterFilterName, Order: -70, Filter: &UserRateLimiterFilter{}},
	RoleFilterName:               {Name: RoleFilterName, Order: -60, Filter: &RoleFilter{}},
	ReplayFilterName:             {Name: ReplayFilterName, Order: -50, Filter: &ReplayFilter{}},
	PostHandleFilterName:         {Name: PostHandleFilterName, Order: math.MaxInt, Filter: &PostHandleFilter{}},
	RenderHandleFilterName:       {Name: RenderHandleFilterName, Order: math.MinInt, Filter: &RenderHandleFilter{}},
}

type NewPostFilter struct{}

func (self *NewPostFilter) DoFilter(chain node.Filter, ctx *node.Context, args ...interface{}) error {
	ctx.AddStorage("httpLog", node.HttpLog{Method: ctx.Path, LogNo: utils.GetSnowFlakeStrID(), CreateAt: utils.UnixMilli()})
	if err := chain.DoFilter(chain, ctx, args...); err != nil {
		return err
	}
	v := ctx.GetStorage("httpLog")
	if v == nil {
		return utils.Error("httpLog is nil")
	}
	httpLog, _ := v.(node.HttpLog)
	httpLog.UpdateAt = utils.UnixMilli()
	httpLog.CostMill = httpLog.UpdateAt - httpLog.CreateAt
	return nil
}

func NewHTTP() *MyWebNode {
	var my = &MyWebNode{}
	my.AddJwtConfig(jwt.JwtConfig{
		TokenTyp: jwt.JWT,
		TokenAlg: jwt.HS256,
		TokenKey: "123456" + utils.CreateLocalSecretKey(12, 45, 23, 60, 58, 30),
		TokenExp: jwt.TWO_WEEK,
	})
	my.AddCacheAware(func(ds ...string) (cache.Cache, error) {
		return local, nil
	})
	my.AddFilter(&node.FilterObject{Name: "NewPostFilter", Order: 100, Filter: &NewPostFilter{}})
	return my
}

// Benchmark test 
goos: darwin
goarch: amd64
cpu: Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz
BenchmarkPubkey
BenchmarkPubkey-8          14770             80893 ns/op             515 B/op          1 allocs/op
BenchmarkPubkey-8          14908             79999 ns/op             515 B/op          1 allocs/op
BenchmarkPubkey-8          15063             79425 ns/op             514 B/op          1 allocs/op
BenchmarkPubkey-8          15031             82307 ns/op             514 B/op          1 allocs/op
BenchmarkPubkey-8          14925             80306 ns/op             515 B/op          1 allocs/op
BenchmarkPubkey-8          15015             79758 ns/op             515 B/op          1 allocs/op
BenchmarkPubkey-8          15133             79156 ns/op             515 B/op          1 allocs/op
BenchmarkPubkey-8          15070             83157 ns/op             515 B/op          1 allocs/op
BenchmarkPubkey-8          14887             79710 ns/op             517 B/op          1 allocs/op
BenchmarkPubkey-8          15061             79666 ns/op             516 B/op          1 allocs/op

3. Create JWT&ECC login demo

// Benchmark test 
goos: windows
goarch: amd64
pkg: github.com/godaddy-x/freego
cpu: 12th Gen Intel(R) Core(TM) i5-12400F
BenchmarkRSALogin
BenchmarkRSALogin-12                4058            293012 ns/op
PASS

4. Create simple ORM demo

func initMysqlDB() {
	conf := sqld.MysqlConfig{}
	if err := utils.ReadLocalJsonConfig("resource/mysql.json", &conf); err != nil {
		panic(utils.AddStr("读取mysql配置失败: ", err.Error()))
	}
	new(sqld.MysqlManager).InitConfigAndCache(nil, conf)
	fmt.Println("init mysql success")
}

func initMongoDB() {
	conf := sqld.MGOConfig{}
	if err := utils.ReadLocalJsonConfig("resource/mongo.json", &conf); err != nil {
		panic(utils.AddStr("读取mongo配置失败: ", err.Error()))
	}
	new(sqld.MGOManager).InitConfigAndCache(nil, conf)
	fmt.Println("init mongo success")
}

func init() {
    sqld.ModelDriver(
	&OwWallet{},
    )
    initMongoDB()
    initMysqlDB()
}

func TestMysqlUpdates(t *testing.T) {
    // db, err := sqld.NewMongo(sqld.Option{OpenTx: true})
	db, err := sqld.NewMysql(sqld.Option{OpenTx: true})
	if err != nil {
		panic(err)
	}
	defer db.Close()
	o1 := OwWallet{
		Id:    123,
		AppID: "123",
	}
	o2 := OwWallet{
		Id:    1234,
		AppID: "1234",
	}
	if err := db.Update(&o1, &o2); err != nil {
		panic(err)
	}
}

func TestMysqlFind(t *testing.T) {
    // db, err := sqld.NewMongo()
	db, err := sqld.NewMysql()
	if err != nil {
		panic(err)
	}
	defer db.Close()
	sql := sqlc.M().Fields("rootPath").Eq("id", 1).Between("index", 10, 50).Gte("index", 30).Like("name", "test").Or(sqlc.M().Eq("id", 12), sqlc.M().Eq("id", 13))
	wallet := OwWallet{}
	if err := db.FindOne(sql, &wallet); err != nil {
		panic(err)
	}
}

5. Create simple Consul&GRPC demo

func init() {
	client := &rpcx.GRPCManager{}
	client.CreateJwtConfig(APPKEY)
	client.CreateAppConfigCall(func(appid string) (rpcx.AppConfig, error) {
		if appid == APPKEY {
			return rpcx.AppConfig{Appid: APPID, Appkey: APPKEY}, nil
		}
		return rpcx.AppConfig{}, utils.Error("appid invalid")
	})
	client.CreateRateLimiterCall(func(method string) (rate.Option, error) {
		return rate.Option{}, nil
	})
	client.CreateServerTLS(rpcx.TlsConfig{
		UseMTLS:   true,
		CACrtFile: "./rpcx/cert/ca.crt",
		KeyFile:   "./rpcx/cert/server.key",
		CrtFile:   "./rpcx/cert/server.crt",
	})
	client.CreateClientTLS(rpcx.TlsConfig{
		UseMTLS:   true,
		CACrtFile: "./rpcx/cert/ca.crt",
		KeyFile:   "./rpcx/cert/client.key",
		CrtFile:   "./rpcx/cert/client.crt",
		HostName:  "localhost",
	})
	client.CreateAuthorizeTLS("./rpcx/cert/server.key")
}

// grpc server
func TestConsulxGRPCServer(t *testing.T) {
	objects := []*rpcx.GRPC{
		{
			Address: "localhost",
			Service: "PubWorker",
			Tags:    []string{"ID Generator"},
			AddRPC:  func(server *grpc.Server) { pb.RegisterPubWorkerServer(server, &impl.PubWorker{}) },
		},
	}
	rpcx.RunServer("", true, objects...)
}

// grpc client
func TestConsulxGRPCClient(t *testing.T) {
	rpcx.RunClient(APPID)
	conn, err := rpcx.NewClientConn(rpcx.GRPC{Service: "PubWorker", Cache: 30})
	if err != nil {
		panic(err)
	}
	defer conn.Close()
	res, err := pb.NewPubWorkerClient(conn.Value()).GenerateId(conn.Context(), &pb.GenerateIdReq{})
	if err != nil {
		panic(err)
	}
	fmt.Println("call result: ", res)
}

// grpc client benchmark test
func BenchmarkGRPCClient(b *testing.B) {
	rpcx.RunClient(APPID)
	b.StopTimer()
	b.StartTimer()
	for i := 0; i < b.N; i++ { //use b.N for looping
		conn, err := rpcx.NewClientConn(rpcx.GRPC{Service: "PubWorker", Cache: 30})
		if err != nil {
			return
		}
		_, err = pb.NewPubWorkerClient(conn.Value()).GenerateId(conn.Context(), &pb.GenerateIdReq{})
		if err != nil {
			return
		}
		conn.Close()
	}
}

BenchmarkGRPCClient-40              11070            212487 ns/op