This is an automated email from the ASF dual-hosted git repository.

chenjunxu pushed a commit to branch refactor
in repository https://gitbox.apache.org/repos/asf/apisix-dashboard.git


The following commit(s) were added to refs/heads/refactor by this push:
     new 79348d9  feat: add store hub and flake id (#534)
79348d9 is described below

commit 79348d9ecbc9991db3a1df73e2c8ba24ae35a6bc
Author: Vinci Xu <[email protected]>
AuthorDate: Fri Oct 2 09:48:11 2020 +0800

    feat: add store hub and flake id (#534)
    
    * feat: add store hub and flake id
    
    * feat: add store interface to easy est
---
 api/go.mod                                         |  2 +
 api/go.sum                                         |  5 ++
 api/internal/core/entity/entity.go                 | 16 ++++-
 api/internal/core/store/store.go                   | 27 ++++++++-
 api/internal/core/store/store_test.go              | 26 +++++---
 api/internal/core/store/storehub.go                | 41 +++++++++++++
 .../store/{validator_mock.go => validate_mock.go}  |  0
 api/internal/handler/consumer/consumer.go          | 21 +------
 api/internal/handler/route/route.go                | 44 ++++++++------
 api/internal/handler/service/service.go            | 21 +------
 api/internal/handler/ssl/ssl.go                    | 21 +------
 api/internal/handler/upstream/upstream.go          | 21 +------
 api/internal/utils/utils.go                        | 63 ++++++++++++++++++++
 api/internal/utils/utils_test.go                   | 16 +++++
 api/main.go                                        | 69 ++++++++++++++++++++++
 15 files changed, 287 insertions(+), 106 deletions(-)

diff --git a/api/go.mod b/api/go.mod
index 1c935ff..face2f0 100644
--- a/api/go.mod
+++ b/api/go.mod
@@ -4,6 +4,7 @@ go 1.13
 
 require (
        github.com/api7/apitest v1.4.9
+       github.com/api7/go-jsonpatch v0.0.0-20180223123257-a8710867776e
        github.com/coreos/etcd v3.3.25+incompatible // indirect
        github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf // 
indirect
        github.com/dgrijalva/jwt-go v3.2.0+incompatible
@@ -20,6 +21,7 @@ require (
        github.com/shiningrush/droplet v0.1.2
        github.com/shiningrush/droplet/wrapper/gin v0.1.0
        github.com/sirupsen/logrus v1.6.0
+       github.com/sony/sonyflake v1.0.0
        github.com/spf13/viper v1.7.1
        github.com/steinfletcher/apitest v1.4.10 // indirect
        github.com/stretchr/testify v1.6.1
diff --git a/api/go.sum b/api/go.sum
index 50b3cdf..6201e29 100644
--- a/api/go.sum
+++ b/api/go.sum
@@ -18,6 +18,8 @@ github.com/alecthomas/template 
v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod 
h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/api7/apitest v1.4.9 h1:FYTUQJ1hgeB9UvMFif1jjbfiA+XqHPEBfsjhDskytA8=
 github.com/api7/apitest v1.4.9/go.mod 
h1:YZruZ+jDMFL6rNgMWiuhwCTugNN0mJkLCYCHG3ICYlE=
+github.com/api7/go-jsonpatch v0.0.0-20180223123257-a8710867776e 
h1:TX/8xM53DHaIIBr4wU+ifYI8IkUzS8+HrX8kzIzaaG0=
+github.com/api7/go-jsonpatch v0.0.0-20180223123257-a8710867776e/go.mod 
h1:yc49guNPyTy2deyszk3erQN+2vO2NwLKPNicXurj7Hs=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod 
h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
 github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod 
h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod 
h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
@@ -46,6 +48,7 @@ github.com/coreos/pkg 
v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc
 github.com/davecgh/go-spew v1.1.0/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 
h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod 
h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/deckarep/golang-set v1.7.1/go.mod 
h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
 github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd 
h1:83Wprp6ROGeiHFAP8WJdI2RoxALQYgdllERc3N5N2DM=
 github.com/denisenkom/go-mssqldb v0.0.0-20191124224453-732737034ffd/go.mod 
h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible 
h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
@@ -291,6 +294,8 @@ github.com/smartystreets/goconvey v1.6.4 
h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIK
 github.com/smartystreets/goconvey v1.6.4/go.mod 
h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
 github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E=
 github.com/soheilhy/cmux v0.1.4/go.mod 
h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/sony/sonyflake v1.0.0 
h1:MpU6Ro7tfXwgn2l5eluf9xQvQJDROTBImNCfRXn/YeM=
+github.com/sony/sonyflake v1.0.0/go.mod 
h1:Jv3cfhf/UFtolOTTRd3q4Nl6ENqM+KfyZ5PseKfZGF4=
 github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod 
h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
 github.com/spf13/afero v1.1.2 h1:m8/z1t7/fwjysjQRYbP0RD+bUIF/8tJwPdEZsI83ACI=
 github.com/spf13/afero v1.1.2/go.mod 
h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
diff --git a/api/internal/core/entity/entity.go 
b/api/internal/core/entity/entity.go
index baad4aa..5dca9c8 100644
--- a/api/internal/core/entity/entity.go
+++ b/api/internal/core/entity/entity.go
@@ -16,8 +16,22 @@
  */
 package entity
 
+type BaseInfo struct {
+       ID         string `json:"id"`
+       CreateTime int64  `json:"create_time"`
+       UpdateTime int64  `json:"update_time"`
+}
+
+func (info *BaseInfo) GetBaseInfo() *BaseInfo {
+       return info
+}
+
+type BaseInfoGetter interface {
+       GetBaseInfo() *BaseInfo
+}
+
 type Route struct {
-       ID              string      `json:"id"`
+       BaseInfo
        URI             string      `json:"uri,omitempty" validate:"uri"`
        Uris            []string    `json:"uris,omitempty"`
        Name            string      `json:"name,omitempty" validate:"max=50"`
diff --git a/api/internal/core/store/store.go b/api/internal/core/store/store.go
index 6b63e6a..3d2d4b9 100644
--- a/api/internal/core/store/store.go
+++ b/api/internal/core/store/store.go
@@ -20,12 +20,23 @@ import (
        "context"
        "encoding/json"
        "fmt"
+       "github.com/apisix/manager-api/internal/core/entity"
        "github.com/apisix/manager-api/internal/core/storage"
+       "github.com/apisix/manager-api/internal/utils"
+       "github.com/shiningrush/droplet/data"
        "log"
        "reflect"
        "time"
 )
 
+type Interface interface {
+       Get(key string) (interface{}, error)
+       List(input ListInput) (*ListOutput, error)
+       Create(ctx context.Context, obj interface{}) error
+       Update(ctx context.Context, obj interface{}) error
+       BatchDelete(ctx context.Context, keys []string) error
+}
+
 type GenericStore struct {
        Stg storage.Interface
 
@@ -114,7 +125,7 @@ func (s *GenericStore) Init() error {
 func (s *GenericStore) Get(key string) (interface{}, error) {
        ret, ok := s.cache[key]
        if !ok {
-               return nil, fmt.Errorf("id:%s not found", key)
+               return nil, data.ErrNotFound
        }
        return ret, nil
 }
@@ -193,6 +204,15 @@ func (s *GenericStore) Create(ctx context.Context, obj 
interface{}) error {
                return fmt.Errorf("key: %s is conflicted", key)
        }
 
+       if getter, ok := obj.(entity.BaseInfoGetter); ok {
+               info := getter.GetBaseInfo()
+               if info.ID == "" {
+                       info.ID = utils.GetFlakeUidStr()
+               }
+               info.CreateTime = time.Now().Unix()
+               info.UpdateTime = time.Now().Unix()
+       }
+
        bs, err := json.Marshal(obj)
        if err != nil {
                return fmt.Errorf("json marshal failed: %s", err)
@@ -218,6 +238,11 @@ func (s *GenericStore) Update(ctx context.Context, obj 
interface{}) error {
                return fmt.Errorf("key: %s is not found", key)
        }
 
+       if getter, ok := obj.(entity.BaseInfoGetter); ok {
+               info := getter.GetBaseInfo()
+               info.UpdateTime = time.Now().Unix()
+       }
+
        bs, err := json.Marshal(obj)
        if err != nil {
                return fmt.Errorf("json marshal failed: %s", err)
diff --git a/api/internal/core/store/store_test.go 
b/api/internal/core/store/store_test.go
index cc074cb..38ab343 100644
--- a/api/internal/core/store/store_test.go
+++ b/api/internal/core/store/store_test.go
@@ -18,7 +18,9 @@ package store
 
 import (
        "context"
+       "encoding/json"
        "fmt"
+       "github.com/apisix/manager-api/internal/core/entity"
        "github.com/apisix/manager-api/internal/core/storage"
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/mock"
@@ -99,6 +101,7 @@ func TestNewGenericStore(t *testing.T) {
 }
 
 type TestStruct struct {
+       entity.BaseInfo
        Field1 string
        Field2 string
 }
@@ -408,7 +411,8 @@ func TestGenericStore_List(t *testing.T) {
 
        for _, tc := range tests {
                ret, err := tc.giveStore.List(tc.giveInput)
-               assert.Equal(t, tc.wantRet, ret, tc.caseDesc)
+               assert.Equal(t, tc.wantRet.TotalSize, ret.TotalSize, 
tc.caseDesc)
+               assert.ElementsMatch(t, tc.wantRet.Rows, ret.Rows, tc.caseDesc)
                assert.Equal(t, tc.wantErr, err, tc.caseDesc)
        }
 }
@@ -472,7 +476,6 @@ func TestGenericStore_Create(t *testing.T) {
                giveErr         error
                giveValidateErr error
                wantKey         string
-               wantStr         string
                wantErr         error
        }{
                {
@@ -490,7 +493,6 @@ func TestGenericStore_Create(t *testing.T) {
                                },
                        },
                        wantKey: "test/path/test1",
-                       wantStr: `{"Field1":"test1","Field2":"test2"}`,
                },
                {
                        caseDesc: "create failed",
@@ -508,7 +510,6 @@ func TestGenericStore_Create(t *testing.T) {
                        },
                        giveErr: fmt.Errorf("create failed"),
                        wantKey: "test/path/test1",
-                       wantStr: `{"Field1":"test1","Field2":"test2"}`,
                        wantErr: fmt.Errorf("create failed"),
                },
                {
@@ -553,7 +554,13 @@ func TestGenericStore_Create(t *testing.T) {
                mStorage.On("Create", mock.Anything, mock.Anything, 
mock.Anything).Run(func(args mock.Arguments) {
                        createCalled = true
                        assert.Equal(t, tc.wantKey, args[1], tc.caseDesc)
-                       assert.Equal(t, tc.wantStr, args[2], tc.caseDesc)
+                       input := TestStruct{}
+                       _ = json.Unmarshal([]byte(args[2].(string)), &input)
+                       assert.Equal(t, tc.giveObj.Field1, input.Field1, 
tc.caseDesc)
+                       assert.Equal(t, tc.giveObj.Field2, input.Field2, 
tc.caseDesc)
+                       assert.NotEqual(t, 0, len(input.ID), tc.caseDesc)
+                       assert.NotEqual(t, 0, input.CreateTime, tc.caseDesc)
+                       assert.NotEqual(t, 0, input.UpdateTime, tc.caseDesc)
                }).Return(tc.giveErr)
 
                mValidator := &MockValidator{}
@@ -582,7 +589,6 @@ func TestGenericStore_Update(t *testing.T) {
                giveErr         error
                giveValidateErr error
                wantKey         string
-               wantStr         string
                wantErr         error
        }{
                {
@@ -603,7 +609,6 @@ func TestGenericStore_Update(t *testing.T) {
                                },
                        },
                        wantKey: "test/path/test1",
-                       wantStr: `{"Field1":"test1","Field2":"test2"}`,
                },
                {
                        caseDesc: "create failed",
@@ -624,7 +629,6 @@ func TestGenericStore_Update(t *testing.T) {
                        },
                        giveErr: fmt.Errorf("create failed"),
                        wantKey: "test/path/test1",
-                       wantStr: `{"Field1":"test1","Field2":"test2"}`,
                        wantErr: fmt.Errorf("create failed"),
                },
                {
@@ -654,7 +658,11 @@ func TestGenericStore_Update(t *testing.T) {
                mStorage.On("Update", mock.Anything, mock.Anything, 
mock.Anything).Run(func(args mock.Arguments) {
                        createCalled = true
                        assert.Equal(t, tc.wantKey, args[1], tc.caseDesc)
-                       assert.Equal(t, tc.wantStr, args[2], tc.caseDesc)
+                       input := TestStruct{}
+                       _ = json.Unmarshal([]byte(args[2].(string)), &input)
+                       assert.Equal(t, tc.giveObj.Field1, input.Field1, 
tc.caseDesc)
+                       assert.Equal(t, tc.giveObj.Field2, input.Field2, 
tc.caseDesc)
+                       assert.NotEqual(t, 0, input.UpdateTime, tc.caseDesc)
                }).Return(tc.giveErr)
 
                mValidator := &MockValidator{}
diff --git a/api/internal/core/store/storehub.go 
b/api/internal/core/store/storehub.go
new file mode 100644
index 0000000..5b26bd3
--- /dev/null
+++ b/api/internal/core/store/storehub.go
@@ -0,0 +1,41 @@
+package store
+
+import (
+       "fmt"
+       "github.com/apisix/manager-api/internal/utils"
+)
+
+type HubKey string
+
+const (
+       HubKeyConsumer HubKey = "consumer"
+       HubKeyRoute    HubKey = "route"
+       HubKeyService  HubKey = "service"
+       HubKeySsl      HubKey = "ssl"
+       HubKeyUpstream HubKey = "upstream"
+)
+
+var (
+       storeHub = map[HubKey]*GenericStore{}
+)
+
+func InitStore(key HubKey, opt GenericStoreOption) error {
+       s, err := NewGenericStore(opt)
+       if err != nil {
+               return err
+       }
+       if err := s.Init(); err != nil {
+               return err
+       }
+
+       utils.AppendToClosers(s.Close)
+       storeHub[key] = s
+       return nil
+}
+
+func GetStore(key HubKey) *GenericStore {
+       if s, ok := storeHub[key]; ok {
+               return s
+       }
+       panic(fmt.Sprintf("no store with key: %s", key))
+}
diff --git a/api/internal/core/store/validator_mock.go 
b/api/internal/core/store/validate_mock.go
similarity index 100%
rename from api/internal/core/store/validator_mock.go
rename to api/internal/core/store/validate_mock.go
diff --git a/api/internal/handler/consumer/consumer.go 
b/api/internal/handler/consumer/consumer.go
index 048b1cc..ed55d39 100644
--- a/api/internal/handler/consumer/consumer.go
+++ b/api/internal/handler/consumer/consumer.go
@@ -29,32 +29,15 @@ import (
        "github.com/apisix/manager-api/internal/core/entity"
        "github.com/apisix/manager-api/internal/core/store"
        "github.com/apisix/manager-api/internal/handler"
-       "github.com/apisix/manager-api/internal/utils"
 )
 
 type Handler struct {
-       consumerStore *store.GenericStore
+       consumerStore store.Interface
 }
 
 func NewHandler() (handler.RouteRegister, error) {
-       s, err := store.NewGenericStore(store.GenericStoreOption{
-               BasePath: "/apisix/consumers",
-               ObjType:  reflect.TypeOf(entity.Consumer{}),
-               KeyFunc: func(obj interface{}) string {
-                       r := obj.(*entity.Consumer)
-                       return r.Username
-               },
-       })
-       if err != nil {
-               return nil, err
-       }
-       if err := s.Init(); err != nil {
-               return nil, err
-       }
-
-       utils.AppendToClosers(s.Close)
        return &Handler{
-               consumerStore: s,
+               consumerStore: store.GetStore(store.HubKeyConsumer),
        }, nil
 }
 
diff --git a/api/internal/handler/route/route.go 
b/api/internal/handler/route/route.go
index 7107555..c46ad12 100644
--- a/api/internal/handler/route/route.go
+++ b/api/internal/handler/route/route.go
@@ -17,6 +17,7 @@
 package route
 
 import (
+       "fmt"
        "reflect"
        "strings"
 
@@ -29,32 +30,19 @@ import (
        "github.com/apisix/manager-api/internal/core/entity"
        "github.com/apisix/manager-api/internal/core/store"
        "github.com/apisix/manager-api/internal/handler"
-       "github.com/apisix/manager-api/internal/utils"
 )
 
 type Handler struct {
-       routeStore *store.GenericStore
+       routeStore    store.Interface
+       svcStore      store.Interface
+       upstreamStore store.Interface
 }
 
 func NewHandler() (handler.RouteRegister, error) {
-       s, err := store.NewGenericStore(store.GenericStoreOption{
-               BasePath: "/apisix/routes",
-               ObjType:  reflect.TypeOf(entity.Route{}),
-               KeyFunc: func(obj interface{}) string {
-                       r := obj.(*entity.Route)
-                       return r.ID
-               },
-       })
-       if err != nil {
-               return nil, err
-       }
-       if err := s.Init(); err != nil {
-               return nil, err
-       }
-
-       utils.AppendToClosers(s.Close)
        return &Handler{
-               routeStore: s,
+               routeStore:    store.GetStore(store.HubKeyRoute),
+               svcStore:      store.GetStore(store.HubKeyService),
+               upstreamStore: store.GetStore(store.HubKeyUpstream),
        }, nil
 }
 
@@ -112,6 +100,24 @@ func (h *Handler) List(c droplet.Context) (interface{}, 
error) {
 
 func (h *Handler) Create(c droplet.Context) (interface{}, error) {
        input := c.Input().(*entity.Route)
+       if input.ServiceID != "" {
+               _, err := h.upstreamStore.Get(input.ServiceID)
+               if err != nil {
+                       if err == data.ErrNotFound {
+                               return nil, fmt.Errorf("service id: %s not 
found", input.ServiceID)
+                       }
+                       return nil, err
+               }
+       }
+       if input.UpstreamID != "" {
+               _, err := h.upstreamStore.Get(input.ServiceID)
+               if err != nil {
+                       if err == data.ErrNotFound {
+                               return nil, fmt.Errorf("upstream id: %s not 
found", input.UpstreamID)
+                       }
+                       return nil, err
+               }
+       }
 
        if err := h.routeStore.Create(c.Context(), input); err != nil {
                return nil, err
diff --git a/api/internal/handler/service/service.go 
b/api/internal/handler/service/service.go
index 2255bdd..ee8b5c5 100644
--- a/api/internal/handler/service/service.go
+++ b/api/internal/handler/service/service.go
@@ -30,32 +30,15 @@ import (
        "github.com/apisix/manager-api/internal/core/entity"
        "github.com/apisix/manager-api/internal/core/store"
        "github.com/apisix/manager-api/internal/handler"
-       "github.com/apisix/manager-api/internal/utils"
 )
 
 type Handler struct {
-       serviceStore *store.GenericStore
+       serviceStore store.Interface
 }
 
 func NewHandler() (handler.RouteRegister, error) {
-       s, err := store.NewGenericStore(store.GenericStoreOption{
-               BasePath: "/apisix/services",
-               ObjType:  reflect.TypeOf(entity.Service{}),
-               KeyFunc: func(obj interface{}) string {
-                       r := obj.(*entity.Service)
-                       return r.ID
-               },
-       })
-       if err != nil {
-               return nil, err
-       }
-       if err := s.Init(); err != nil {
-               return nil, err
-       }
-
-       utils.AppendToClosers(s.Close)
        return &Handler{
-               serviceStore: s,
+               serviceStore: store.GetStore(store.HubKeyService),
        }, nil
 }
 
diff --git a/api/internal/handler/ssl/ssl.go b/api/internal/handler/ssl/ssl.go
index 46d4126..52162fb 100644
--- a/api/internal/handler/ssl/ssl.go
+++ b/api/internal/handler/ssl/ssl.go
@@ -35,32 +35,15 @@ import (
        "github.com/apisix/manager-api/internal/core/entity"
        "github.com/apisix/manager-api/internal/core/store"
        "github.com/apisix/manager-api/internal/handler"
-       "github.com/apisix/manager-api/internal/utils"
 )
 
 type Handler struct {
-       sslStore *store.GenericStore
+       sslStore store.Interface
 }
 
 func NewHandler() (handler.RouteRegister, error) {
-       s, err := store.NewGenericStore(store.GenericStoreOption{
-               BasePath: "/apisix/ssl",
-               ObjType:  reflect.TypeOf(entity.SSL{}),
-               KeyFunc: func(obj interface{}) string {
-                       r := obj.(*entity.SSL)
-                       return r.ID
-               },
-       })
-       if err != nil {
-               return nil, err
-       }
-       if err := s.Init(); err != nil {
-               return nil, err
-       }
-
-       utils.AppendToClosers(s.Close)
        return &Handler{
-               sslStore: s,
+               sslStore: store.GetStore(store.HubKeySsl),
        }, nil
 }
 
diff --git a/api/internal/handler/upstream/upstream.go 
b/api/internal/handler/upstream/upstream.go
index 1c0b41b..87a8dd0 100644
--- a/api/internal/handler/upstream/upstream.go
+++ b/api/internal/handler/upstream/upstream.go
@@ -30,32 +30,15 @@ import (
        "github.com/apisix/manager-api/internal/core/entity"
        "github.com/apisix/manager-api/internal/core/store"
        "github.com/apisix/manager-api/internal/handler"
-       "github.com/apisix/manager-api/internal/utils"
 )
 
 type Handler struct {
-       upstreamStore *store.GenericStore
+       upstreamStore store.Interface
 }
 
 func NewHandler() (handler.RouteRegister, error) {
-       s, err := store.NewGenericStore(store.GenericStoreOption{
-               BasePath: "/apisix/upstreams",
-               ObjType:  reflect.TypeOf(entity.Upstream{}),
-               KeyFunc: func(obj interface{}) string {
-                       r := obj.(*entity.Upstream)
-                       return r.ID
-               },
-       })
-       if err != nil {
-               return nil, err
-       }
-       if err := s.Init(); err != nil {
-               return nil, err
-       }
-
-       utils.AppendToClosers(s.Close)
        return &Handler{
-               upstreamStore: s,
+               upstreamStore: store.GetStore(store.HubKeyUpstream),
        }, nil
 }
 
diff --git a/api/internal/utils/utils.go b/api/internal/utils/utils.go
new file mode 100644
index 0000000..f28c1bf
--- /dev/null
+++ b/api/internal/utils/utils.go
@@ -0,0 +1,63 @@
+package utils
+
+import (
+       "github.com/sony/sonyflake"
+       "net"
+       "os"
+       "strconv"
+)
+
+var _sf *sonyflake.Sonyflake
+
+func init() {
+       saltStr, ok := os.LookupEnv("FLAKE_SALT")
+       var salt uint16
+       if ok {
+               i, err := strconv.Atoi(saltStr)
+               if err != nil {
+                       panic(err)
+               }
+               salt = uint16(i)
+       }
+
+       _sf = sonyflake.NewSonyflake(sonyflake.Settings{
+               MachineID: func() (u uint16, e error) {
+                       return sumIP(GetOutboundIP()) + salt, nil
+               },
+       })
+       if _sf == nil {
+               panic("sonyflake init failed")
+       }
+}
+
+func sumIP(ip net.IP) uint16 {
+       total := 0
+       for i := range ip {
+               total += int(ip[i])
+       }
+       return uint16(total)
+}
+
+// Get preferred outbound ip of this machine
+func GetOutboundIP() net.IP {
+       conn, err := net.Dial("udp", "8.8.8.8:80")
+       if err != nil {
+               panic(err)
+       }
+       defer conn.Close()
+
+       localAddr := conn.LocalAddr().(*net.UDPAddr)
+       return localAddr.IP
+}
+
+func GetFlakeUid() uint64 {
+       uid, err := _sf.NextID()
+       if err != nil {
+               panic("get sony flake uid failed:" + err.Error())
+       }
+       return uid
+}
+
+func GetFlakeUidStr() string {
+       return strconv.FormatUint(GetFlakeUid(), 10)
+}
diff --git a/api/internal/utils/utils_test.go b/api/internal/utils/utils_test.go
new file mode 100644
index 0000000..f88a6e4
--- /dev/null
+++ b/api/internal/utils/utils_test.go
@@ -0,0 +1,16 @@
+package utils
+
+import (
+       "github.com/stretchr/testify/assert"
+       "testing"
+)
+
+func TestGetFlakeUid(t *testing.T) {
+       id := GetFlakeUid()
+       assert.NotEqual(t, 0, id)
+}
+
+func TestGetFlakeUidStr(t *testing.T) {
+       id := GetFlakeUidStr()
+       assert.NotEqual(t, "", id)
+}
diff --git a/api/main.go b/api/main.go
index 9638045..36541b7 100644
--- a/api/main.go
+++ b/api/main.go
@@ -18,10 +18,13 @@ package main
 
 import (
        "fmt"
+       "github.com/apisix/manager-api/internal/core/entity"
        "github.com/apisix/manager-api/internal/core/storage"
+       "github.com/apisix/manager-api/internal/core/store"
        "github.com/apisix/manager-api/internal/utils"
        "github.com/spf13/viper"
        "net/http"
+       "reflect"
        "strings"
        "time"
 
@@ -41,6 +44,9 @@ func main() {
        if err := 
storage.InitETCDClient(strings.Split(viper.GetString("etcd_endpoints"), ",")); 
err != nil {
                panic(err)
        }
+       if err := initStores(); err != nil {
+               panic(err)
+       }
 
        // init
        //conf.InitializeMysql()
@@ -59,3 +65,66 @@ func main() {
 
        utils.CloseAll()
 }
+
+func initStores() error {
+       err := store.InitStore(store.HubKeyConsumer, store.GenericStoreOption{
+               BasePath: "/apisix/consumers",
+               ObjType:  reflect.TypeOf(entity.Consumer{}),
+               KeyFunc: func(obj interface{}) string {
+                       r := obj.(*entity.Consumer)
+                       return r.Username
+               },
+       })
+       if err != nil {
+               return err
+       }
+
+       err = store.InitStore(store.HubKeyRoute, store.GenericStoreOption{
+               BasePath: "/apisix/routes",
+               ObjType:  reflect.TypeOf(entity.Route{}),
+               KeyFunc: func(obj interface{}) string {
+                       r := obj.(*entity.Route)
+                       return r.ID
+               },
+       })
+       if err != nil {
+               return err
+       }
+
+       err = store.InitStore(store.HubKeyService, store.GenericStoreOption{
+               BasePath: "/apisix/services",
+               ObjType:  reflect.TypeOf(entity.Service{}),
+               KeyFunc: func(obj interface{}) string {
+                       r := obj.(*entity.Service)
+                       return r.ID
+               },
+       })
+       if err != nil {
+               return err
+       }
+
+       err = store.InitStore(store.HubKeySsl, store.GenericStoreOption{
+               BasePath: "/apisix/ssl",
+               ObjType:  reflect.TypeOf(entity.SSL{}),
+               KeyFunc: func(obj interface{}) string {
+                       r := obj.(*entity.SSL)
+                       return r.ID
+               },
+       })
+       if err != nil {
+               return err
+       }
+
+       err = store.InitStore(store.HubKeyUpstream, store.GenericStoreOption{
+               BasePath: "/apisix/upstreams",
+               ObjType:  reflect.TypeOf(entity.Upstream{}),
+               KeyFunc: func(obj interface{}) string {
+                       r := obj.(*entity.Upstream)
+                       return r.ID
+               },
+       })
+       if err != nil {
+               return err
+       }
+       return nil
+}

Reply via email to