diff --git a/cmd/migration/conf/.gitkeeper b/cmd/migration/conf/.gitkeeper deleted file mode 100644 index e69de29..0000000 diff --git a/cmd/migration/main.go b/cmd/migration/main.go deleted file mode 100644 index f1e8694..0000000 --- a/cmd/migration/main.go +++ /dev/null @@ -1,7 +0,0 @@ -package main - -import "another_node/internal/community/storage/migrations" - -func main() { - migrations.Rollback() -} diff --git a/conf/appsettings.yaml b/conf/appsettings.yaml index 27e7db8..0e2ce2a 100644 --- a/conf/appsettings.yaml +++ b/conf/appsettings.yaml @@ -15,4 +15,5 @@ node: externalAddr: "0.0.0.0" externalPort: 7946 bindAddr: "0.0.0.0" - bindPort: 7946 \ No newline at end of file + bindPort: 7946 +storage: another.dat \ No newline at end of file diff --git a/conf/conf.go b/conf/conf.go index 02d13d9..cd82e97 100644 --- a/conf/conf.go +++ b/conf/conf.go @@ -11,10 +11,10 @@ import ( var once sync.Once type Conf struct { - Web Web - Db DB - Jwt JWT - Node Node + Web Web + Jwt JWT + Node Node + Storage string } var conf *Conf @@ -45,10 +45,18 @@ func getConfiguration(filePath *string) *Conf { func mappingEnvToConf(fileConf *Conf) (envConf *Conf) { envConf = &Conf{ Web: Web{}, - Db: DB{}, Jwt: JWT{}, Node: Node{}, } + + if storage := os.Getenv("storage"); len(storage) > 0 { + envConf.Storage = storage + } else if fileConf != nil { + envConf.Storage = fileConf.Storage + } else { + envConf.Storage = "another.dat" + } + if web__port := os.Getenv("web__port"); len(web__port) > 0 { if port, err := strconv.Atoi(web__port); err == nil && port > 0 { envConf.Web.Port = port @@ -62,26 +70,6 @@ func mappingEnvToConf(fileConf *Conf) (envConf *Conf) { panic("web.port is invalid") } } - if db__user := os.Getenv("db__user"); len(db__user) > 0 { - envConf.Db.User = db__user - } else if fileConf != nil { - envConf.Db.User = fileConf.Db.User - } - if db__password := os.Getenv("db__password"); len(db__password) > 0 { - envConf.Db.Password = db__password - } else if fileConf != nil { - envConf.Db.Password = fileConf.Db.Password - } - if db__host := os.Getenv("db__host"); len(db__host) > 0 { - envConf.Db.Host = db__host - } else if fileConf != nil { - envConf.Db.Host = fileConf.Db.Host - } - if db__schema := os.Getenv("db__schema"); len(db__schema) > 0 { - envConf.Db.Schema = db__schema - } else if fileConf != nil { - envConf.Db.Schema = fileConf.Db.Schema - } if jwt__security := os.Getenv("jwt__security"); len(jwt__security) > 0 { envConf.Jwt.Security = jwt__security diff --git a/conf/conn.go b/conf/conn.go deleted file mode 100644 index ff2ae04..0000000 --- a/conf/conn.go +++ /dev/null @@ -1,61 +0,0 @@ -package conf - -import ( - "fmt" - "os" - "sync" - - "gorm.io/driver/postgres" - "gorm.io/driver/sqlite" - "gorm.io/gorm" -) - -type DB struct { - User string - Password string - Host string - Schema string -} - -var db *gorm.DB - -func getDbConnectionString(c *Conf) *string { - // - dsn := fmt.Sprintf("postgres://%s:%s@%s/%s", c.Db.User, c.Db.Password, c.Db.Host, c.Db.Schema) - return &dsn -} - -var onceDb sync.Once - -// GetDbClient 获取数据库连接对象 -func GetDbClient() *gorm.DB { - onceDb.Do(func() { - if os.Getenv("UnitTestEnv") == "1" || os.Getenv("LocalDebug") == "true" { - db, _ = getInMemoryDbClient() - db = db.Debug() - } else { - dsn := getDbConnectionString(getConf()) - _db, err := gorm.Open(postgres.Open(*dsn), &gorm.Config{ - DisableForeignKeyConstraintWhenMigrating: true, - }) - if err != nil { - panic(err) - } - - if Environment.IsDevelopment() { - _db = _db.Debug() - } - db = _db - } - }) - return db -} - -// getInMemoryDbClient 获取内存数据库对象,仅限单元测试使用 -func getInMemoryDbClient() (*gorm.DB, error) { - if client, err := gorm.Open(sqlite.Open("file::memory:?cache=private"), &gorm.Config{}); err != nil { - return nil, err - } else { - return client, nil - } -} diff --git a/conf/storage.go b/conf/storage.go new file mode 100644 index 0000000..acc2424 --- /dev/null +++ b/conf/storage.go @@ -0,0 +1,15 @@ +package conf + +import ( + "os" + + "github.com/syndtr/goleveldb/leveldb/storage" +) + +func GetStorage() (storage.Storage, error) { + if os.Getenv("UnitTest") == "1" { + return storage.NewMemStorage(), nil + } else { + return storage.OpenFile(getConf().Storage, false) + } +} diff --git a/go.mod b/go.mod index 8f44016..2a7b0fd 100644 --- a/go.mod +++ b/go.mod @@ -5,22 +5,21 @@ go 1.22.1 require ( github.com/gin-gonic/gin v1.9.1 github.com/hashicorp/memberlist v0.5.1 - github.com/stretchr/testify v1.9.0 github.com/swaggo/swag v1.16.3 + github.com/syndtr/goleveldb v1.0.0 gopkg.in/yaml.v2 v2.4.0 - gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde ) require ( github.com/KyleBanks/depth v1.2.1 // indirect github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect github.com/chenzhuoyu/iasm v0.9.1 // indirect - github.com/davecgh/go-spew v1.1.1 // indirect github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/spec v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c // indirect github.com/hashicorp/errwrap v1.0.0 // indirect github.com/hashicorp/go-immutable-radix v1.0.0 // indirect @@ -28,19 +27,10 @@ require ( github.com/hashicorp/go-multierror v1.0.0 // indirect github.com/hashicorp/go-sockaddr v1.0.0 // indirect github.com/hashicorp/golang-lru v0.5.0 // indirect - github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/pgx/v5 v5.5.4 // indirect - github.com/jackc/puddle/v2 v2.2.1 // indirect - github.com/jinzhu/inflection v1.0.0 // indirect - github.com/jinzhu/now v1.1.5 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/mailru/easyjson v0.7.7 // indirect - github.com/mattn/go-sqlite3 v1.14.17 // indirect github.com/miekg/dns v1.1.26 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect - golang.org/x/sync v0.7.0 // indirect golang.org/x/tools v0.20.0 // indirect ) @@ -74,6 +64,4 @@ require ( golang.org/x/text v0.14.0 // indirect google.golang.org/protobuf v1.33.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - gorm.io/driver/postgres v1.5.7 - gorm.io/driver/sqlite v1.5.5 ) diff --git a/go.sum b/go.sum index a61b32e..7418f39 100644 --- a/go.sum +++ b/go.sum @@ -20,6 +20,7 @@ github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLI 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/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= github.com/gin-contrib/cors v1.7.1 h1:s9SIppU/rk8enVvkzwiC2VK3UZ/0NNGsWfUKvV55rqs= @@ -50,6 +51,10 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= +github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= @@ -73,18 +78,8 @@ github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCO github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/memberlist v0.5.1 h1:mk5dRuzeDNis2bi6LLoQIXfMH7JQvAzt3mQD0vNZZUo= github.com/hashicorp/memberlist v0.5.1/go.mod h1:zGDXV6AqbDTKTM6yxW0I4+JtFzZAJVoIPvss4hV8F24= -github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= -github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.5.4 h1:Xp2aQS8uXButQdnCMWNmvx6UysWQQC+u1EoizjguY+8= -github.com/jackc/pgx/v5 v5.5.4/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= -github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= -github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= -github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= -github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -103,8 +98,6 @@ github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= -github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/miekg/dns v1.1.26 h1:gPxPSwALAeHJSjarOs00QjVdV9QoBvc1D2ujQUr5BzU= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -112,6 +105,11 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pelletier/go-toml/v2 v2.2.0 h1:QLgLl2yMN7N+ruc31VynXs1vhMZa7CeHHejIeBAsoHo= @@ -140,6 +138,8 @@ github.com/swaggo/gin-swagger v1.6.0 h1:y8sxvQ3E20/RCyrXeFfg60r6H0Z+SwpTjMYsMm+z github.com/swaggo/gin-swagger v1.6.0/go.mod h1:BG00cCEy294xtVpyIAHG6+e2Qzj/xKlRdOqDkvq0uzo= github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= +github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= @@ -162,6 +162,7 @@ golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -170,10 +171,12 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -207,16 +210,15 @@ google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHh gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gorm.io/driver/postgres v1.5.7 h1:8ptbNJTDbEmhdr62uReG5BGkdQyeasu/FZHxI0IMGnM= -gorm.io/driver/postgres v1.5.7/go.mod h1:3e019WlBaYI5o5LIdNV+LyxCMNtLOQETBXL2h4chKpA= -gorm.io/driver/sqlite v1.5.5 h1:7MDMtUZhV065SilG62E0MquljeArQZNfJnjd9i9gx3E= -gorm.io/driver/sqlite v1.5.5/go.mod h1:6NgQ7sQWAIFsPrJJl1lSNSu2TABh0ZZ/zm5fosATavE= -gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde h1:9DShaph9qhkIYw7QF91I/ynrr4cOO2PZra2PFD7Mfeg= -gorm.io/gorm v1.25.7-0.20240204074919-46816ad31dde/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/internal/community/storage/conf/.gitkeeper b/internal/community/storage/conf/.gitkeeper deleted file mode 100644 index e69de29..0000000 diff --git a/internal/community/storage/member.go b/internal/community/storage/member.go index 1367696..84ee838 100644 --- a/internal/community/storage/member.go +++ b/internal/community/storage/member.go @@ -3,39 +3,119 @@ package storage import ( "another_node/conf" "errors" - "time" + "fmt" + "strconv" + "strings" - "gorm.io/gorm" + "github.com/syndtr/goleveldb/leveldb" ) // Member represent a web2 account type Member struct { - Model - HashedAccount string `gorm:"column:hashed_account; type:varchar(1024); not null; uniqueIndex"` - RpcAddress string `gorm:"column:rpc_address; type:varchar(128); not null"` - RpcPort int `gorm:"column:rpc_port; type:int; not null; default:0"` - PublicKey string `gorm:"column:public_key; type:varchar(1024)"` - PrivateKeyVault *string `gorm:"column:private_key_vault; type:varchar(1024); null"` + HashedAccount string + RpcAddress string + RpcPort int + PublicKey string + PrivateKeyVault *string + Version uint } -func (m *Member) TableName() string { - return "members" +const ( + hashedAccountCapacity = 128 + rpcAddressCapacity = 128 + rpcPortCapacity = 5 + publicKeyCapacity = 1024 + privateKeyVaultCapacity = 2048 +) + +func (m *Member) Marshal() []byte { + hashedAccount := fmt.Sprintf("%-*s", hashedAccountCapacity, m.HashedAccount) + if len(hashedAccount) > hashedAccountCapacity { + hashedAccount = hashedAccount[:hashedAccountCapacity] + } + + rpcAddress := fmt.Sprintf("%-*s", rpcAddressCapacity, m.RpcAddress) + if len(rpcAddress) > rpcAddressCapacity { + rpcAddress = rpcAddress[:rpcAddressCapacity] + } + + rpcPort := fmt.Sprintf("%-*d", rpcPortCapacity, m.RpcPort) + if len(rpcPort) > rpcPortCapacity { + rpcPort = rpcPort[:rpcPortCapacity] + } + + publicKey := fmt.Sprintf("%-*s", publicKeyCapacity, m.PublicKey) + if len(publicKey) > publicKeyCapacity { + publicKey = publicKey[:publicKeyCapacity] + } + + privateKeyVault := fmt.Sprintf("%-*s", privateKeyVaultCapacity, *m.PrivateKeyVault) + if len(privateKeyVault) > privateKeyVaultCapacity { + privateKeyVault = privateKeyVault[:privateKeyVaultCapacity] + } + + result := hashedAccount + rpcAddress + rpcPort + publicKey + privateKeyVault + return []byte(result) +} + +func Unmarshal(data []byte) (*Member, error) { + if len(data) < (hashedAccountCapacity + rpcAddressCapacity + rpcPortCapacity + publicKeyCapacity + privateKeyVaultCapacity) { + return nil, errors.New("data is too short to unmarshal into Member") + } + + hashedAccount := strings.TrimSpace(string(data[:hashedAccountCapacity])) + rpcAddress := strings.TrimSpace(string(data[hashedAccountCapacity : hashedAccountCapacity+rpcAddressCapacity])) + rpcPort, err := strconv.Atoi(strings.TrimSpace(string(data[hashedAccountCapacity+rpcAddressCapacity : hashedAccountCapacity+rpcAddressCapacity+rpcPortCapacity]))) + if err != nil { + return nil, err + } + publicKey := strings.TrimSpace(string(data[hashedAccountCapacity+rpcAddressCapacity+rpcPortCapacity : hashedAccountCapacity+rpcAddressCapacity+rpcPortCapacity+publicKeyCapacity])) + privateKeyVault := strings.TrimSpace(string(data[hashedAccountCapacity+rpcAddressCapacity+rpcPortCapacity+publicKeyCapacity:])) + + return &Member{ + HashedAccount: hashedAccount, + RpcAddress: rpcAddress, + RpcPort: rpcPort, + PublicKey: publicKey, + PrivateKeyVault: &privateKeyVault, + }, nil +} + +func compareAndUpdateMember(oldMember, newMember *Member) *Member { + if oldMember.Version >= newMember.Version { + return oldMember + } + + if len(newMember.PublicKey) == 0 { + newMember.PublicKey = oldMember.PublicKey + } + + if newMember.PrivateKeyVault == nil { + newMember.PrivateKeyVault = oldMember.PrivateKeyVault + } + + if len(newMember.RpcAddress) == 0 || newMember.RpcPort == 0 { + newMember.RpcAddress = oldMember.RpcAddress + newMember.RpcPort = oldMember.RpcPort + } + + return newMember } // UpsertMember update a member if exists and newer than old by version func UpsertMember(hashedAccount, publicKey, privateKey, rpcAddress string, rpcPort int, version *int) error { - db := conf.GetDbClient() - - return db.Transaction(func(tx *gorm.DB) error { - var member Member - err := tx.Where("hashed_account = ?", hashedAccount).First(&member).Error - if errors.Is(err, gorm.ErrRecordNotFound) { - return tx.Omit("updated_at", "id").Create(&Member{ - Model: Model{ - CreatedAt: time.Now(), - Version: uint(*version), - }, + if stor, err := conf.GetStorage(); err != nil { + return err + } else { + if db, err := leveldb.Open(stor, nil); err != nil { + return err + } else { + defer db.Close() + + newMember := &Member{ HashedAccount: hashedAccount, + RpcAddress: rpcAddress, + RpcPort: rpcPort, PublicKey: publicKey, PrivateKeyVault: func() *string { if len(privateKey) == 0 { @@ -44,69 +124,44 @@ func UpsertMember(hashedAccount, publicKey, privateKey, rpcAddress string, rpcPo return &privateKey } }(), - RpcAddress: rpcAddress, - RpcPort: rpcPort, - }).Error - } else { - if member.Version >= uint(*version) { - *version = int(member.Version) - return nil + Version: uint(*version), } + if oldMemberByte, err := db.Get([]byte(hashedAccount), nil); err != nil { + if errors.Is(err, leveldb.ErrNotFound) { + return db.Put([]byte(hashedAccount), newMember.Marshal(), nil) + } + return err + } else { + if oldMember, err := Unmarshal(oldMemberByte); err != nil { + return err + } else { + newMember = compareAndUpdateMember(oldMember, newMember) - if len(publicKey) == 0 { - tx.Omit("public_key") - } - if len(privateKey) == 0 { - tx.Omit("private_key_vault") - } - if len(rpcAddress) == 0 || rpcPort == 0 { - tx.Omit("rpc_address") - tx.Omit("rpc_port") - } - err := tx.Where("id=?", member.ID).Updates(Member{ - PublicKey: func() string { - if len(publicKey) > 0 { - return publicKey - } else { - return member.PublicKey - } - }(), - PrivateKeyVault: func() *string { - if len(privateKey) > 0 { - return &privateKey - } else { - return member.PrivateKeyVault - } - }(), - RpcAddress: func() string { - if len(rpcAddress) > 0 { - return rpcAddress - } else { - return member.RpcAddress - } - }(), - RpcPort: func() int { - if rpcPort > 0 { - return rpcPort - } else { - return member.RpcPort - } - }(), - }).Error + return db.Put([]byte(hashedAccount), newMember.Marshal(), nil) + } - return err + } } - }) + } } // TryFindMember find a member by hashed account func TryFindMember(hashedAccount string) (*Member, error) { - db := conf.GetDbClient() - - var member Member - err := db.Where("hashed_account = ?", hashedAccount).First(&member).Error - if errors.Is(err, gorm.ErrRecordNotFound) { - return nil, nil + if stor, err := conf.GetStorage(); err != nil { + return nil, err + } else { + if db, err := leveldb.Open(stor, nil); err != nil { + return nil, err + } else { + defer db.Close() + if member, err := db.Get([]byte(hashedAccount), nil); err != nil { + if errors.Is(err, leveldb.ErrNotFound) { + return nil, nil + } + return nil, err + } else { + return Unmarshal(member) + } + } } - return &member, err } diff --git a/internal/community/storage/member_test.go b/internal/community/storage/member_test.go index 271b331..269f4e1 100644 --- a/internal/community/storage/member_test.go +++ b/internal/community/storage/member_test.go @@ -1,45 +1,60 @@ package storage import ( - "os" + "fmt" + "reflect" "testing" - - "github.com/stretchr/testify/assert" ) -func TestMember(t *testing.T) { - if err := os.Setenv("UnitTestEnv", "1"); err != nil { - t.Skip("skipped due to CI") - } else { - defer os.Unsetenv("UnitTestEnv") +func TestMarshal(t *testing.T) { + privateKey := "privateKey" + member := &Member{ + HashedAccount: "hashedAccount", + RpcAddress: "rpcAddress", + RpcPort: 12345, + PublicKey: "publicKey", + PrivateKeyVault: &privateKey, } - prepare_test() - ptr := "B" - prtN := 1 - ver := 1 - assert.NoError(t, UpsertMember("A", ptr, ptr, ptr, prtN, &ver)) - assert.NoError(t, UpsertMember("A", ptr, ptr, ptr, prtN, &ver)) -} + data := member.Marshal() + + hashedAccount := fmt.Sprintf("%-*s", hashedAccountCapacity, "hashedAccount") + rpcAddress := fmt.Sprintf("%-*s", rpcAddressCapacity, "rpcAddress") + rpcPort := fmt.Sprintf("%-*d", rpcPortCapacity, 12345) + publicKey := fmt.Sprintf("%-*s", publicKeyCapacity, "publicKey") + privateKeyVault := fmt.Sprintf("%-*s", privateKeyVaultCapacity, "privateKey") -func TestFindMember(t *testing.T) { - if err := os.Setenv("UnitTestEnv", "1"); err != nil { - t.Skip("skipped due to CI") - } else { - defer os.Unsetenv("UnitTestEnv") + expected := []byte(hashedAccount + rpcAddress + rpcPort + publicKey + privateKeyVault) + + if !reflect.DeepEqual(data, expected) { + t.Errorf("Expected %v, but got %v", expected, data) } - prepare_test() +} - ptrN := 1 - ver := 1 +func TestUnmarshal(t *testing.T) { + privateKey := "privateKey" - ptr := "B" - assert.NoError(t, UpsertMember("A", ptr, ptr, ptr, ptrN, &ver)) - ptr = "C" - assert.NoError(t, UpsertMember("A", ptr, ptr, ptr, ptrN, &ver)) + hashedAccount := fmt.Sprintf("%-*s", hashedAccountCapacity, "hashedAccount") + rpcAddress := fmt.Sprintf("%-*s", rpcAddressCapacity, "rpcAddress") + rpcPort := fmt.Sprintf("%-*d", rpcPortCapacity, 12345) + publicKey := fmt.Sprintf("%-*s", publicKeyCapacity, "publicKey") + privateKeyVault := fmt.Sprintf("%-*s", privateKeyVaultCapacity, privateKey) - member, err := TryFindMember("A") - assert.NoError(t, err) - assert.NotNil(t, member) - assert.Equal(t, "B", member.PublicKey) + data := []byte(hashedAccount + rpcAddress + rpcPort + publicKey + privateKeyVault) + member, err := Unmarshal(data) + + if err != nil { + t.Errorf("Expected no error, but got %v", err) + } + + expected := &Member{ + HashedAccount: "hashedAccount", + RpcAddress: "rpcAddress", + RpcPort: 12345, + PublicKey: "publicKey", + PrivateKeyVault: &privateKey, + } + if !reflect.DeepEqual(member, expected) { + t.Errorf("Expected %v, but got %v", expected, member) + } } diff --git a/internal/community/storage/migrations/migrate.go b/internal/community/storage/migrations/migrate.go deleted file mode 100644 index 03123fc..0000000 --- a/internal/community/storage/migrations/migrate.go +++ /dev/null @@ -1,50 +0,0 @@ -package migrations - -import ( - "another_node/conf" - - "gorm.io/gorm" -) - -type Migration interface { - Up(db *gorm.DB) error - Down(db *gorm.DB) error -} - -var migrations []Migration - -func init() { - // Migration objects must be added in order from old to new - migrations = []Migration{ - &Migration20240420{}, - } - -} - -func AutoMigrate() { - db := conf.GetDbClient() - - // TODO: Check if there is a latest change record in the '__migration' table, if so, skip the migration - migrate(db) -} - -// migrate synchronizes database changes -func migrate(db *gorm.DB) { - - for i := 0; i < len(migrations); i++ { - migrations[i].Up(db) - } -} - -// rollback rolls back database changes -func rollback(db *gorm.DB) { - - for i := len(migrations) - 1; i >= 0; i-- { - migrations[i].Down(db) - } -} - -func Rollback() { - db := conf.GetDbClient() - rollback(db) -} diff --git a/internal/community/storage/migrations/migrate_test.go b/internal/community/storage/migrations/migrate_test.go deleted file mode 100644 index 8dc5857..0000000 --- a/internal/community/storage/migrations/migrate_test.go +++ /dev/null @@ -1,94 +0,0 @@ -package migrations - -import ( - "another_node/conf" - "os" - "testing" - - "github.com/stretchr/testify/assert" - "gorm.io/gorm" -) - -var sortedUp, sortedDown []int - -type migration001 struct { -} - -func (m *migration001) Up(_ *gorm.DB) error { - println("[up]001") - sortedUp = append(sortedUp, 1) - return nil -} - -func (m *migration001) Down(_ *gorm.DB) error { - println("[down]001") - sortedDown = append(sortedDown, 1) - return nil -} - -type migration002 struct { -} - -func (m *migration002) Up(_ *gorm.DB) error { - println("[up]002") - sortedUp = append(sortedUp, 2) - return nil -} - -func (m *migration002) Down(_ *gorm.DB) error { - println("[down]002") - sortedDown = append(sortedDown, 2) - return nil -} - -func initTestData() { - sortedUp = make([]int, 0) - sortedDown = make([]int, 0) - - migrations = []Migration{ - &migration001{}, - &migration002{}, - } -} -func TestMigrate(t *testing.T) { - initTestData() - migrate(nil) - - if testing.Short() { - assert.Equal(t, 1, sortedUp[0]) - assert.Equal(t, 2, sortedUp[1]) - } -} - -func TestRollback(t *testing.T) { - var db *gorm.DB - - if testing.Short() { - initTestData() - } else { - db = conf.GetDbClient() - } - - rollback(db) - - if testing.Short() { - assert.Equal(t, 2, sortedDown[0]) - assert.Equal(t, 1, sortedDown[1]) - } -} - -func TestAutoMigrate(t *testing.T) { - var db *gorm.DB - if err := os.Setenv("UnitTestEnv", "1"); err != nil { - t.Skip("skipped due to CI") - } else { - defer os.Unsetenv("UnitTestEnv") - } - - db = conf.GetDbClient() - - m1 := &Migration20240420{} - - assert.NoError(t, m1.Up(db)) - assert.NoError(t, m1.Down(db)) -} diff --git a/internal/community/storage/migrations/migration20240420.go b/internal/community/storage/migrations/migration20240420.go deleted file mode 100644 index b175b75..0000000 --- a/internal/community/storage/migrations/migration20240420.go +++ /dev/null @@ -1,30 +0,0 @@ -package migrations - -import ( - "another_node/internal/community/storage" - - "gorm.io/gorm" -) - -type Migration20240420 struct { -} - -func (m *Migration20240420) Up(db *gorm.DB) error { - if !db.Migrator().HasTable(&storage.Member{}) { - if err := db.AutoMigrate(&storage.Member{}); err != nil { - return err - } - } - - return nil -} - -func (m *Migration20240420) Down(db *gorm.DB) error { - if err := db.Migrator().DropTable( - &storage.Member{}, - ); err != nil { - return err - } - - return nil -} diff --git a/internal/community/storage/storage_test.go b/internal/community/storage/storage_test.go deleted file mode 100644 index 772788e..0000000 --- a/internal/community/storage/storage_test.go +++ /dev/null @@ -1,9 +0,0 @@ -package storage - -import "another_node/conf" - -func prepare_test() { - db := conf.GetDbClient() - - db.AutoMigrate(&Member{}) -} diff --git a/internal/community/storage/type.go b/internal/community/storage/type.go deleted file mode 100644 index 2dc394a..0000000 --- a/internal/community/storage/type.go +++ /dev/null @@ -1,16 +0,0 @@ -package storage - -import ( - "time" - - "gorm.io/gorm" -) - -type Model struct { - ID uint `gorm:"column:id; primarykey"` - CreatedAt time.Time `gorm:"column:created_at; autoCreateTime"` - UpdatedAt time.Time `gorm:"column:updated_at; autoUpdateTime:milli"` - DeletedAt gorm.DeletedAt `gorm:"column:deleted_at; index"` - DeletedBy string `gorm:"column:deleted_by; type: varchar(1024); null"` - Version uint `gorm:"column:version; default:0;"` -} diff --git a/main.go b/main.go index e9ec7d2..ff128f7 100644 --- a/main.go +++ b/main.go @@ -4,7 +4,6 @@ import ( "another_node/conf" "another_node/internal/community" "another_node/internal/community/node" - "another_node/internal/community/storage/migrations" "another_node/internal/web_server/routers" "flag" "strconv" @@ -38,8 +37,6 @@ func main() { community.New(n) } - migrations.AutoMigrate() - // start web server routers.SetRouters().Run(func(port int) string { if port == 0 {