diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d1f1bc669..58e06e0de4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,12 +22,15 @@ Changelog for NeoFS Node - Internal container cache size from 10 to 1000 (#2600) - Transaction witness scope no longer uses CustomGroups relying on more strict Rules now (#2619) - New optimized SDK version is integrated (#2622) +- IR uses internal LOCODE DB from Go package (#2610) ### Removed - deprecated `no-precheck` flag of `neofs-cli container set-eacl` (#2496) - Recently-handled objects Policer's cache (#2600) - deprecated blobovnicza substorage (#2614) - Contract group wallet support from `neofs-adm` (#2619) +- `neofs-cli util locode generate`and `neofs-cli util locode info` commands (#2610) +- Locode DB configuration options (#2610) ### Updated - Update minimal supported Go version up to v1.19 (#2485) diff --git a/cmd/neofs-cli/modules/util/locode.go b/cmd/neofs-cli/modules/util/locode.go deleted file mode 100644 index 1e267eba76..0000000000 --- a/cmd/neofs-cli/modules/util/locode.go +++ /dev/null @@ -1,18 +0,0 @@ -package util - -import ( - "github.com/spf13/cobra" -) - -// locode section. -var locodeCmd = &cobra.Command{ - Use: "locode", - Short: "Working with NeoFS UN/LOCODE database", -} - -func initLocodeCmd() { - locodeCmd.AddCommand(locodeGenerateCmd, locodeInfoCmd) - - initUtilLocodeInfoCmd() - initUtilLocodeGenerateCmd() -} diff --git a/cmd/neofs-cli/modules/util/locode_generate.go b/cmd/neofs-cli/modules/util/locode_generate.go deleted file mode 100644 index 613ded54ae..0000000000 --- a/cmd/neofs-cli/modules/util/locode_generate.go +++ /dev/null @@ -1,97 +0,0 @@ -package util - -import ( - "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common" - locodedb "github.com/nspcc-dev/neofs-node/pkg/util/locode/db" - airportsdb "github.com/nspcc-dev/neofs-node/pkg/util/locode/db/airports" - locodebolt "github.com/nspcc-dev/neofs-node/pkg/util/locode/db/boltdb" - continentsdb "github.com/nspcc-dev/neofs-node/pkg/util/locode/db/continents/geojson" - csvlocode "github.com/nspcc-dev/neofs-node/pkg/util/locode/table/csv" - "github.com/spf13/cobra" -) - -type namesDB struct { - *airportsdb.DB - *csvlocode.Table -} - -const ( - locodeGenerateInputFlag = "in" - locodeGenerateSubDivFlag = "subdiv" - locodeGenerateAirportsFlag = "airports" - locodeGenerateCountriesFlag = "countries" - locodeGenerateContinentsFlag = "continents" - locodeGenerateOutputFlag = "out" -) - -var ( - locodeGenerateInPaths []string - locodeGenerateSubDivPath string - locodeGenerateAirportsPath string - locodeGenerateCountriesPath string - locodeGenerateContinentsPath string - locodeGenerateOutPath string - - locodeGenerateCmd = &cobra.Command{ - Use: "generate", - Short: "Generate UN/LOCODE database for NeoFS", - Args: cobra.NoArgs, - Run: func(cmd *cobra.Command, _ []string) { - locodeDB := csvlocode.New( - csvlocode.Prm{ - Path: locodeGenerateInPaths[0], - SubDivPath: locodeGenerateSubDivPath, - }, - csvlocode.WithExtraPaths(locodeGenerateInPaths[1:]...), - ) - - airportDB := airportsdb.New(airportsdb.Prm{ - AirportsPath: locodeGenerateAirportsPath, - CountriesPath: locodeGenerateCountriesPath, - }) - - continentsDB := continentsdb.New(continentsdb.Prm{ - Path: locodeGenerateContinentsPath, - }) - - targetDB := locodebolt.New(locodebolt.Prm{ - Path: locodeGenerateOutPath, - }) - - err := targetDB.Open() - common.ExitOnErr(cmd, "", err) - - defer targetDB.Close() - - names := &namesDB{ - DB: airportDB, - Table: locodeDB, - } - - err = locodedb.FillDatabase(locodeDB, airportDB, continentsDB, names, targetDB) - common.ExitOnErr(cmd, "", err) - }, - } -) - -func initUtilLocodeGenerateCmd() { - flags := locodeGenerateCmd.Flags() - - flags.StringSliceVar(&locodeGenerateInPaths, locodeGenerateInputFlag, nil, "List of paths to UN/LOCODE tables (csv)") - _ = locodeGenerateCmd.MarkFlagRequired(locodeGenerateInputFlag) - - flags.StringVar(&locodeGenerateSubDivPath, locodeGenerateSubDivFlag, "", "Path to UN/LOCODE subdivision database (csv)") - _ = locodeGenerateCmd.MarkFlagRequired(locodeGenerateSubDivFlag) - - flags.StringVar(&locodeGenerateAirportsPath, locodeGenerateAirportsFlag, "", "Path to OpenFlights airport database (csv)") - _ = locodeGenerateCmd.MarkFlagRequired(locodeGenerateAirportsFlag) - - flags.StringVar(&locodeGenerateCountriesPath, locodeGenerateCountriesFlag, "", "Path to OpenFlights country database (csv)") - _ = locodeGenerateCmd.MarkFlagRequired(locodeGenerateCountriesFlag) - - flags.StringVar(&locodeGenerateContinentsPath, locodeGenerateContinentsFlag, "", "Path to continent polygons (GeoJSON)") - _ = locodeGenerateCmd.MarkFlagRequired(locodeGenerateContinentsFlag) - - flags.StringVar(&locodeGenerateOutPath, locodeGenerateOutputFlag, "", "Target path for generated database") - _ = locodeGenerateCmd.MarkFlagRequired(locodeGenerateOutputFlag) -} diff --git a/cmd/neofs-cli/modules/util/locode_info.go b/cmd/neofs-cli/modules/util/locode_info.go deleted file mode 100644 index 555ed4aa15..0000000000 --- a/cmd/neofs-cli/modules/util/locode_info.go +++ /dev/null @@ -1,57 +0,0 @@ -package util - -import ( - "github.com/nspcc-dev/neofs-node/cmd/neofs-cli/internal/common" - locodedb "github.com/nspcc-dev/neofs-node/pkg/util/locode/db" - locodebolt "github.com/nspcc-dev/neofs-node/pkg/util/locode/db/boltdb" - "github.com/spf13/cobra" -) - -const ( - locodeInfoDBFlag = "db" - locodeInfoCodeFlag = "locode" -) - -var ( - locodeInfoDBPath string - locodeInfoCode string - - locodeInfoCmd = &cobra.Command{ - Use: "info", - Short: "Print information about UN/LOCODE from NeoFS database", - Args: cobra.NoArgs, - Run: func(cmd *cobra.Command, _ []string) { - targetDB := locodebolt.New(locodebolt.Prm{ - Path: locodeInfoDBPath, - }, locodebolt.ReadOnly()) - - err := targetDB.Open() - common.ExitOnErr(cmd, "", err) - - defer targetDB.Close() - - record, err := locodedb.LocodeRecord(targetDB, locodeInfoCode) - common.ExitOnErr(cmd, "", err) - - cmd.Printf("Country: %s\n", record.CountryName()) - cmd.Printf("Location: %s\n", record.LocationName()) - cmd.Printf("Continent: %s\n", record.Continent()) - if subDivCode := record.SubDivCode(); subDivCode != "" { - cmd.Printf("Subdivision: [%s] %s\n", subDivCode, record.SubDivName()) - } - - geoPoint := record.GeoPoint() - cmd.Printf("Coordinates: %0.2f, %0.2f\n", geoPoint.Latitude(), geoPoint.Longitude()) - }, - } -) - -func initUtilLocodeInfoCmd() { - flags := locodeInfoCmd.Flags() - - flags.StringVar(&locodeInfoDBPath, locodeInfoDBFlag, "", "Path to NeoFS UN/LOCODE database") - _ = locodeInfoCmd.MarkFlagRequired(locodeInfoDBFlag) - - flags.StringVar(&locodeInfoCode, locodeInfoCodeFlag, "", "UN/LOCODE") - _ = locodeInfoCmd.MarkFlagRequired(locodeInfoCodeFlag) -} diff --git a/cmd/neofs-cli/modules/util/root.go b/cmd/neofs-cli/modules/util/root.go index be29631430..a2c4180ac8 100644 --- a/cmd/neofs-cli/modules/util/root.go +++ b/cmd/neofs-cli/modules/util/root.go @@ -23,11 +23,9 @@ func init() { signCmd, convertCmd, keyerCmd, - locodeCmd, ) initSignCmd() initConvertCmd() initKeyerCmd() - initLocodeCmd() } diff --git a/cmd/neofs-ir/defaults.go b/cmd/neofs-ir/defaults.go index 331d31c80c..86e78c5b5c 100644 --- a/cmd/neofs-ir/defaults.go +++ b/cmd/neofs-ir/defaults.go @@ -99,8 +99,6 @@ func defaultConfiguration(cfg *viper.Viper) { cfg.SetDefault("indexer.cache_timeout", 15*time.Second) - cfg.SetDefault("locode.db.path", "") - // extra fee values for working mode without notary contract cfg.SetDefault("fee.main_chain", 5000_0000) // 0.5 Fixed8 cfg.SetDefault("fee.side_chain", 2_0000_0000) // 2.0 Fixed8 diff --git a/config/example/ir.env b/config/example/ir.env index d40914a088..de5b46f139 100644 --- a/config/example/ir.env +++ b/config/example/ir.env @@ -24,8 +24,6 @@ NEOFS_IR_GOVERNANCE_DISABLE=false NEOFS_IR_NODE_PERSISTENT_STATE_PATH=.neofs-ir-state -NEOFS_IR_LOCODE_DB_PATH=/path/to/locode.db - NEOFS_IR_FEE_MAIN_CHAIN=50000000 NEOFS_IR_TIMERS_EMIT=240 diff --git a/config/example/ir.yaml b/config/example/ir.yaml index 19a61d7600..3781ba50e8 100644 --- a/config/example/ir.yaml +++ b/config/example/ir.yaml @@ -156,10 +156,6 @@ node: persistent_state: path: .neofs-ir-state # Path to application state file -locode: - db: - path: /path/to/locode.db # Path to UN/LOCODE database file - fee: main_chain: 50000000 # Fixed8 value of extra GAS fee for mainchain contract invocation; ignore if notary is enabled in mainchain diff --git a/go.mod b/go.mod index 96c0621ee6..3cdd707be0 100644 --- a/go.mod +++ b/go.mod @@ -15,6 +15,7 @@ require ( github.com/multiformats/go-multiaddr v0.12.0 github.com/nats-io/nats.go v1.31.0 github.com/nspcc-dev/hrw v1.0.9 + github.com/nspcc-dev/locode-db v0.4.1-0.20231110164540-a21ea2774f2e github.com/nspcc-dev/neo-go v0.103.1 github.com/nspcc-dev/neofs-api-go/v2 v2.14.0 github.com/nspcc-dev/neofs-contract v0.18.0 @@ -22,7 +23,6 @@ require ( github.com/nspcc-dev/tzhash v1.7.1 github.com/olekukonko/tablewriter v0.0.5 github.com/panjf2000/ants/v2 v2.8.2 - github.com/paulmach/orb v0.10.0 github.com/prometheus/client_golang v1.17.0 github.com/spf13/cast v1.5.1 github.com/spf13/cobra v1.7.0 @@ -94,7 +94,6 @@ require ( github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 // indirect github.com/twmb/murmur3 v1.1.5 // indirect github.com/urfave/cli v1.22.5 // indirect - go.mongodb.org/mongo-driver v1.11.4 // indirect go.uber.org/multierr v1.10.0 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect diff --git a/go.sum b/go.sum index 063a2a34ef..297d4e98a7 100644 --- a/go.sum +++ b/go.sum @@ -94,7 +94,6 @@ github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbS github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -187,8 +186,8 @@ github.com/ipfs/go-cid v0.3.2/go.mod h1:gQ8pKqT/sUxGY+tIwy1RPpAojYu7jAyCp5Tz1svo github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4= github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -222,7 +221,6 @@ github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mmcloughlin/addchain v0.4.0 h1:SobOdjm2xLj1KkXN5/n0xTIWyZA2+s99UCY1iPfkHRY= github.com/mmcloughlin/addchain v0.4.0/go.mod h1:A86O+tHqZLMNO4w6ZZ4FlVQEadcoqkyU72HC5wJ4RlU= github.com/mmcloughlin/profile v0.1.1/go.mod h1:IhHD7q1ooxgwTgjxQYkACGA77oFTDdFVejUS1/tS/qU= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o= github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc= github.com/multiformats/go-base32 v0.1.0 h1:pVx9xoSPqEIQG8o+UbAe7DNi51oej1NtK+aGkbLYxPE= @@ -249,8 +247,8 @@ github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 h1:n4ZaF github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22/go.mod h1:79bEUDEviBHJMFV6Iq6in57FEOCMcRhfQnfaf0ETA5U= github.com/nspcc-dev/hrw v1.0.9 h1:17VcAuTtrstmFppBjfRiia4K2wA/ukXZhLFS8Y8rz5Y= github.com/nspcc-dev/hrw v1.0.9/go.mod h1:l/W2vx83vMQo6aStyx2AuZrJ+07lGv2JQGlVkPG06MU= -github.com/nspcc-dev/neo-go v0.103.0 h1:UVyWPhzZdfYFG35ORP3FRDLh8J/raRQ6m8SptDdlgfM= -github.com/nspcc-dev/neo-go v0.103.0/go.mod h1:x+wmcYqpZYJwLp1l/pHZrqNp3RSWlkMymWGDij3/OPo= +github.com/nspcc-dev/locode-db v0.4.1-0.20231110164540-a21ea2774f2e h1:mcL78g9av0/CYVrgMgGqRJLwZAfvLdIaoaPnEDLC6n8= +github.com/nspcc-dev/locode-db v0.4.1-0.20231110164540-a21ea2774f2e/go.mod h1:M+v8C+t9vwYbIVEdTPX/0w2LFRY+FJnYbVUdrzq7iWQ= github.com/nspcc-dev/neo-go v0.103.1 h1:BfRBceHUu8jSc1KQy7CzmQ/pa+xzAmgcyteGf0/IGgM= github.com/nspcc-dev/neo-go v0.103.1/go.mod h1:MD7MPiyshUwrE5n1/LzxeandbItaa/iLW/bJb6gNs/U= github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20231020160724-c3955f87d1b5 h1:09CpI5uwsxb1EeFPIKQRwwWlfCmDD/Dwwh01lPiQScM= @@ -280,9 +278,6 @@ github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= github.com/panjf2000/ants/v2 v2.8.2 h1:D1wfANttg8uXhC9149gRt1PDQ+dLVFjNXkCEycMcvQQ= github.com/panjf2000/ants/v2 v2.8.2/go.mod h1:7ZxyxsqE4vvW0M7LSD8aI3cKwgFhBHbxnlN8mDqHa1I= -github.com/paulmach/orb v0.10.0 h1:guVYVqzxHE/CQ1KpfGO077TR0ATHSNjp4s6XGLn3W9s= -github.com/paulmach/orb v0.10.0/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU= -github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY= github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4= github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM= @@ -332,7 +327,6 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= @@ -343,26 +337,18 @@ github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8 github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954 h1:xQdMZ1WLrgkkvOZ/LDQxjVxMLdby7osSh4ZEVa5sIjs= github.com/syndtr/goleveldb v1.0.1-0.20210305035536-64b5b1c73954/go.mod h1:u2MKkTVTVJWe5D1rCvame8WqhBd88EuIwODJZ1VHCPM= -github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/twmb/murmur3 v1.1.5 h1:i9OLS9fkuLzBXjt6dptlAEyk58fJsSTXbRg3SgVyqgk= github.com/twmb/murmur3 v1.1.5/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74 h1:JwtAtbp7r/7QSyGz8mKUbYJBg2+6Cd7OjM8o/GNOcVo= github.com/virtuald/go-ordered-json v0.0.0-20170621173500-b18e6e673d74/go.mod h1:RmMWU37GKR2s6pgrIEB4ixgpVCt/cf7dnJv3fuH1J1c= -github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= -github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= -go.mongodb.org/mongo-driver v1.11.4 h1:4ayjakA013OdpGyL2K3ZqylTac/rMjrJOMZ1EHizXas= -go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -381,7 +367,6 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= @@ -581,7 +566,6 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -590,7 +574,6 @@ golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= @@ -693,7 +676,6 @@ google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGj google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/pkg/innerring/innerring.go b/pkg/innerring/innerring.go index 0ecc0381b9..c1703ad919 100644 --- a/pkg/innerring/innerring.go +++ b/pkg/innerring/innerring.go @@ -5,7 +5,6 @@ import ( "encoding/hex" "errors" "fmt" - "io" "net" "sync" "sync/atomic" @@ -312,18 +311,10 @@ func (s *Server) registerNoErrCloser(c func()) { }) } -func (s *Server) registerIOCloser(c io.Closer) { - s.registerCloser(c.Close) -} - func (s *Server) registerCloser(f func() error) { s.closers = append(s.closers, f) } -func (s *Server) registerStarter(f func() error) { - s.starters = append(s.starters, f) -} - // New creates instance of inner ring sever structure. func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper, errChan chan<- error) (*Server, error) { var err error @@ -773,7 +764,7 @@ func New(ctx context.Context, log *zap.Logger, cfg *viper.Viper, errChan chan<- settlement.WithLogger(server.log), ) - locodeValidator, err := server.newLocodeValidator(cfg) + locodeValidator, err := server.newLocodeValidator() if err != nil { return nil, err } diff --git a/pkg/innerring/locode.go b/pkg/innerring/locode.go index 01720f9846..1bf831e7aa 100644 --- a/pkg/innerring/locode.go +++ b/pkg/innerring/locode.go @@ -3,51 +3,8 @@ package innerring import ( "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/netmap" irlocode "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/netmap/nodevalidation/locode" - "github.com/nspcc-dev/neofs-node/pkg/util/locode" - locodedb "github.com/nspcc-dev/neofs-node/pkg/util/locode/db" - locodebolt "github.com/nspcc-dev/neofs-node/pkg/util/locode/db/boltdb" - "github.com/spf13/viper" ) -func (s *Server) newLocodeValidator(cfg *viper.Viper) (netmap.NodeValidator, error) { - locodeDB := locodebolt.New(locodebolt.Prm{ - Path: cfg.GetString("locode.db.path"), - }, - locodebolt.ReadOnly(), - ) - - s.registerStarter(locodeDB.Open) - s.registerIOCloser(locodeDB) - - return irlocode.New(irlocode.Prm{ - DB: (*locodeBoltDBWrapper)(locodeDB), - }), nil -} - -type locodeBoltEntryWrapper struct { - *locodedb.Key - *locodedb.Record -} - -func (l *locodeBoltEntryWrapper) LocationName() string { - return l.Record.LocationName() -} - -type locodeBoltDBWrapper locodebolt.DB - -func (l *locodeBoltDBWrapper) Get(lc *locode.LOCODE) (irlocode.Record, error) { - key, err := locodedb.NewKey(*lc) - if err != nil { - return nil, err - } - - rec, err := (*locodebolt.DB)(l).Get(*key) - if err != nil { - return nil, err - } - - return &locodeBoltEntryWrapper{ - Key: key, - Record: rec, - }, nil +func (s *Server) newLocodeValidator() (netmap.NodeValidator, error) { + return irlocode.New(), nil } diff --git a/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go b/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go index 8d78c1d965..d806f959e2 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go +++ b/pkg/innerring/processors/netmap/nodevalidation/locode/calls.go @@ -1,15 +1,11 @@ package locode import ( - "errors" "fmt" - "github.com/nspcc-dev/neofs-node/pkg/util/locode" "github.com/nspcc-dev/neofs-sdk-go/netmap" ) -var errMissingRequiredAttr = errors.New("missing required attribute in DB record") - // VerifyAndUpdate validates UN-LOCODE attribute of n // and adds a group of related attributes. // @@ -19,72 +15,25 @@ var errMissingRequiredAttr = errors.New("missing required attribute in DB record // If n contains UN-LOCODE attribute and its value does not // match the UN/LOCODE format, an error is returned. // -// New attributes are formed from the record of DB instance (Prm). -// If DB entry R was found w/o errors, new attributes are: -// - CountryCode: R.CountryCode().String(); -// - Country: R.CountryName(); -// - Location: Record.LocationName(); -// - SubDivCode: R.SubDivCode(); -// - SubDiv: R.SubDivName(); -// - Continent: R.Continent().String(). -// // UN-LOCODE attribute remains untouched. func (v *Validator) VerifyAndUpdate(n *netmap.NodeInfo) error { - attrLocode := n.LOCODE() - if attrLocode == "" { + if n.LOCODE() == "" { return nil } - - lc, err := locode.FromString(attrLocode) - if err != nil { - return fmt.Errorf("invalid locode value: %w", err) - } - - record, err := v.db.Get(lc) + key, record, err := v.Get(n.LOCODE()) if err != nil { return fmt.Errorf("could not get locode record from DB: %w", err) } - countryCode := record.CountryCode() - if countryCode == nil { - return errMissingRequiredAttr - } - - strCountryCode := countryCode.String() - if strCountryCode == "" { - return errMissingRequiredAttr - } - - countryName := record.CountryName() - if countryName == "" { - return errMissingRequiredAttr - } - - locationName := record.LocationName() - if locationName == "" { - return errMissingRequiredAttr - } - - continent := record.Continent() - if continent == nil { - return errMissingRequiredAttr - } - - continentName := continent.String() - if continentName == "" { - return errMissingRequiredAttr - } - - n.SetCountryCode(strCountryCode) - n.SetCountryName(countryName) - n.SetLocationName(locationName) - n.SetContinentName(continentName) - - if subDivCode := record.SubDivCode(); subDivCode != "" { + n.SetCountryCode(key.CountryCode().String()) + n.SetCountryName(record.Country) + n.SetLocationName(record.Location) + n.SetContinentName(record.Cont.String()) + if subDivCode := record.SubDivCode; subDivCode != "" { n.SetSubdivisionCode(subDivCode) } - if subDivName := record.SubDivName(); subDivName != "" { + if subDivName := record.SubDivName; subDivName != "" { n.SetSubdivisionName(subDivName) } diff --git a/pkg/innerring/processors/netmap/nodevalidation/locode/calls_test.go b/pkg/innerring/processors/netmap/nodevalidation/locode/calls_test.go index ab17e34ba7..053e62c168 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/locode/calls_test.go +++ b/pkg/innerring/processors/netmap/nodevalidation/locode/calls_test.go @@ -1,44 +1,20 @@ package locode_test import ( - "errors" "fmt" "testing" + "github.com/nspcc-dev/locode-db/pkg/locodedb" "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/netmap/nodevalidation/locode" - locodestd "github.com/nspcc-dev/neofs-node/pkg/util/locode" - locodedb "github.com/nspcc-dev/neofs-node/pkg/util/locode/db" "github.com/nspcc-dev/neofs-sdk-go/netmap" "github.com/stretchr/testify/require" ) -type record struct { - *locodedb.Key - *locodedb.Record -} - -type db struct { - items map[locodestd.LOCODE]locode.Record -} - -func (x db) add(lc locodestd.LOCODE, rec locode.Record) { - x.items[lc] = rec -} - -func (x db) Get(lc *locodestd.LOCODE) (locode.Record, error) { - r, ok := x.items[*lc] - if !ok { - return nil, errors.New("record not found") - } - - return r, nil -} - func addLocodeAttrValue(n *netmap.NodeInfo, val string) { n.SetLOCODE(val) } -func addLocodeAttr(n *netmap.NodeInfo, lc locodestd.LOCODE) { +func addLocodeAttr(n *netmap.NodeInfo, lc [2]string) { n.SetLOCODE(fmt.Sprintf("%s %s", lc[0], lc[1])) } @@ -51,43 +27,23 @@ func nodeInfoWithSomeAttrs() *netmap.NodeInfo { return &n } -func TestValidator_VerifyAndUpdate(t *testing.T) { - db := &db{ - items: make(map[locodestd.LOCODE]locode.Record), +func TestValidator_VerifyAndUpdate(t *testing.T) { // test record with valid but random values + r := locodedb.Record{ + SubDivCode: "MSK", } - // test record with valid but random values - r := locodestd.Record{ - LOCODE: locodestd.LOCODE{"RU", "MOW"}, - NameWoDiacritics: "Moskva", - SubDiv: "MSK", - } - - k, err := locodedb.NewKey(r.LOCODE) - require.NoError(t, err) - - rdb, err := locodedb.NewRecord(r) + k, err := locodedb.NewKey("RU", "MOW") require.NoError(t, err) - - rdb.SetCountryName("Russia") - rdb.SetSubDivName("Moskva oblast") + r.Location = "Moskva" + r.Country = "Russia" + r.SubDivName = "Moskva" + r.SubDivCode = "MOW" var cont locodedb.Continent = locodedb.ContinentEurope - rdb.SetContinent(&cont) - - rec := record{ - Key: k, - Record: rdb, - } - - db.add(r.LOCODE, rec) - - var p locode.Prm + r.Cont = &cont - p.DB = db - - validator := locode.New(p) + validator := locode.New() t.Run("w/o locode", func(t *testing.T) { n := nodeInfoWithSomeAttrs() @@ -99,7 +55,6 @@ func TestValidator_VerifyAndUpdate(t *testing.T) { t.Run("w/ locode", func(t *testing.T) { t.Run("invalid locode", func(t *testing.T) { n := nodeInfoWithSomeAttrs() - addLocodeAttrValue(n, "WRONG LOCODE") err := validator.VerifyAndUpdate(n) @@ -109,7 +64,7 @@ func TestValidator_VerifyAndUpdate(t *testing.T) { t.Run("missing DB record", func(t *testing.T) { n := nodeInfoWithSomeAttrs() - addLocodeAttr(n, locodestd.LOCODE{"RU", "SPB"}) + addLocodeAttr(n, [2]string{"RU", "SPB"}) //RU,SSR -Saint Petersburg err := validator.VerifyAndUpdate(n) require.Error(t, err) @@ -117,16 +72,16 @@ func TestValidator_VerifyAndUpdate(t *testing.T) { n := nodeInfoWithSomeAttrs() - addLocodeAttr(n, r.LOCODE) + addLocodeAttr(n, [2]string{k.CountryCode().String(), k.LocationCode().String()}) err := validator.VerifyAndUpdate(n) require.NoError(t, err) - require.Equal(t, rec.CountryCode().String(), n.Attribute("CountryCode")) - require.Equal(t, rec.CountryName(), n.Attribute("Country")) - require.Equal(t, rec.LocationName(), n.Attribute("Location")) - require.Equal(t, rec.SubDivCode(), n.Attribute("SubDivCode")) - require.Equal(t, rec.SubDivName(), n.Attribute("SubDiv")) - require.Equal(t, rec.Continent().String(), n.Attribute("Continent")) + require.Equal(t, k.CountryCode().String(), n.Attribute("CountryCode")) + require.Equal(t, r.Country, n.Attribute("Country")) + require.Equal(t, r.Location, n.Attribute("Location")) + require.Equal(t, r.SubDivCode, n.Attribute("SubDivCode")) + require.Equal(t, r.SubDivName, n.Attribute("SubDiv")) + require.Equal(t, r.Cont.String(), n.Attribute("Continent")) }) } diff --git a/pkg/innerring/processors/netmap/nodevalidation/locode/deps.go b/pkg/innerring/processors/netmap/nodevalidation/locode/deps.go deleted file mode 100644 index 5a5078ff8d..0000000000 --- a/pkg/innerring/processors/netmap/nodevalidation/locode/deps.go +++ /dev/null @@ -1,59 +0,0 @@ -package locode - -import ( - "github.com/nspcc-dev/neofs-node/pkg/util/locode" - locodedb "github.com/nspcc-dev/neofs-node/pkg/util/locode/db" -) - -// Record is an interface of read-only -// NeoFS LOCODE database single entry. -type Record interface { - // Must return ISO 3166-1 alpha-2 - // country code. - // - // Must not return nil. - CountryCode() *locodedb.CountryCode - - // Must return English short country name - // officially used by the ISO 3166 - // Maintenance Agency (ISO 3166/MA). - CountryName() string - - // Must return UN/LOCODE 3-character code - // for the location (numerals 2-9 may also - // be used). - // - // Must not return nil. - LocationCode() *locodedb.LocationCode - - // Must return name of the location which - // have been allocated a UN/LOCODE without - // diacritic sign. - LocationName() string - - // Must return ISO 1-3 character alphabetic - // and/or numeric code for the administrative - // division of the country concerned. - SubDivCode() string - - // Must return subdivision name. - SubDivName() string - - // Must return existing continent where is - // the location. - // - // Must not return nil. - Continent() *locodedb.Continent -} - -// DB is an interface of read-only -// NeoFS LOCODE database. -type DB interface { - // Must find the record that corresponds to - // LOCODE and provides the Record interface. - // - // Must return an error if Record is nil. - // - // LOCODE is always non-nil. - Get(*locode.LOCODE) (Record, error) -} diff --git a/pkg/innerring/processors/netmap/nodevalidation/locode/validator.go b/pkg/innerring/processors/netmap/nodevalidation/locode/validator.go index 639eb16516..573d8af5b4 100644 --- a/pkg/innerring/processors/netmap/nodevalidation/locode/validator.go +++ b/pkg/innerring/processors/netmap/nodevalidation/locode/validator.go @@ -1,16 +1,8 @@ package locode -// Prm groups the required parameters of the Validator's constructor. -// -// All values must comply with the requirements imposed on them. -// Passing incorrect parameter values will result in constructor -// failure (error or panic depending on the implementation). -type Prm struct { - // NeoFS LOCODE database interface. - // - // Must not be nil. - DB DB -} +import ( + "github.com/nspcc-dev/locode-db/pkg/locodedb" +) // Validator is a utility that verifies and updates // node attributes associated with its geographical location @@ -21,7 +13,6 @@ type Prm struct { // and optional components. After successful creation, // the Validator is immediately ready to work through API. type Validator struct { - db DB } // New creates a new instance of the Validator. @@ -30,8 +21,19 @@ type Validator struct { // // The created Validator does not require additional // initialization and is completely ready for work. -func New(prm Prm) *Validator { - return &Validator{ - db: prm.DB, +func New() *Validator { + return &Validator{} +} + +func (v *Validator) Get(lc string) (*locodedb.Key, locodedb.Record, error) { + country, location := lc[:2], lc[2:] + if lc[2] == ' ' { + location = lc[3:] + } + key, err := locodedb.NewKey(country, location) + if err != nil { + return nil, locodedb.Record{}, err } + rec, err := locodedb.Get(lc) + return key, rec, err } diff --git a/pkg/util/locode/column/coordinates.go b/pkg/util/locode/column/coordinates.go deleted file mode 100644 index 95656345f0..0000000000 --- a/pkg/util/locode/column/coordinates.go +++ /dev/null @@ -1,193 +0,0 @@ -package locodecolumn - -import ( - "fmt" - "strings" - - "github.com/nspcc-dev/neofs-node/pkg/util/locode" -) - -const ( - minutesDigits = 2 - hemisphereSymbols = 1 -) - -const ( - latDegDigits = 2 - lngDegDigits = 3 -) - -type coordinateCode struct { - degDigits int - value []uint8 -} - -// LongitudeCode represents the value of the longitude -// of the location conforming to UN/LOCODE specification. -type LongitudeCode coordinateCode - -// LongitudeHemisphere represents the hemisphere of the earth -// // along the Greenwich meridian. -type LongitudeHemisphere [hemisphereSymbols]uint8 - -// LatitudeCode represents the value of the latitude -// of the location conforming to UN/LOCODE specification. -type LatitudeCode coordinateCode - -// LatitudeHemisphere represents the hemisphere of the earth -// along the equator. -type LatitudeHemisphere [hemisphereSymbols]uint8 - -func coordinateFromString(s string, degDigits int, hemisphereAlphabet []uint8) (*coordinateCode, error) { - if len(s) != degDigits+minutesDigits+hemisphereSymbols { - return nil, locode.ErrInvalidString - } - - for i := range s[:degDigits+minutesDigits] { - if !isDigit(s[i]) { - return nil, locode.ErrInvalidString - } - } - -loop: - for _, sym := range s[degDigits+minutesDigits:] { - for j := range hemisphereAlphabet { - if hemisphereAlphabet[j] == uint8(sym) { - continue loop - } - } - - return nil, locode.ErrInvalidString - } - - return &coordinateCode{ - degDigits: degDigits, - value: []uint8(s), - }, nil -} - -// LongitudeFromString parses a string and returns the location's longitude. -func LongitudeFromString(s string) (*LongitudeCode, error) { - cc, err := coordinateFromString(s, lngDegDigits, []uint8{'W', 'E'}) - if err != nil { - return nil, err - } - - return (*LongitudeCode)(cc), nil -} - -// LatitudeFromString parses a string and returns the location's latitude. -func LatitudeFromString(s string) (*LatitudeCode, error) { - cc, err := coordinateFromString(s, latDegDigits, []uint8{'N', 'S'}) - if err != nil { - return nil, err - } - - return (*LatitudeCode)(cc), nil -} - -func (cc *coordinateCode) degrees() []uint8 { - return cc.value[:cc.degDigits] -} - -// Degrees returns the longitude's degrees. -func (lc *LongitudeCode) Degrees() (l [lngDegDigits]uint8) { - copy(l[:], (*coordinateCode)(lc).degrees()) - return -} - -// Degrees returns the latitude's degrees. -func (lc *LatitudeCode) Degrees() (l [latDegDigits]uint8) { - copy(l[:], (*coordinateCode)(lc).degrees()) - return -} - -func (cc *coordinateCode) minutes() (mnt [minutesDigits]uint8) { - for i := 0; i < minutesDigits; i++ { - mnt[i] = cc.value[cc.degDigits+i] - } - - return -} - -// Minutes returns the longitude's minutes. -func (lc *LongitudeCode) Minutes() [minutesDigits]uint8 { - return (*coordinateCode)(lc).minutes() -} - -// Minutes returns the latitude's minutes. -func (lc *LatitudeCode) Minutes() [minutesDigits]uint8 { - return (*coordinateCode)(lc).minutes() -} - -// Hemisphere returns the longitude's hemisphere code. -func (lc *LongitudeCode) Hemisphere() LongitudeHemisphere { - return (*coordinateCode)(lc).hemisphere() -} - -// Hemisphere returns the latitude's hemisphere code. -func (lc *LatitudeCode) Hemisphere() LatitudeHemisphere { - return (*coordinateCode)(lc).hemisphere() -} - -func (cc *coordinateCode) hemisphere() (h [hemisphereSymbols]uint8) { - for i := 0; i < hemisphereSymbols; i++ { - h[i] = cc.value[cc.degDigits+minutesDigits+i] - } - - return h -} - -// North returns true for the northern hemisphere. -func (h LatitudeHemisphere) North() bool { - return h[0] == 'N' -} - -// East returns true for the eastern hemisphere. -func (h LongitudeHemisphere) East() bool { - return h[0] == 'E' -} - -// Coordinates represents the coordinates of the location from UN/LOCODE table. -type Coordinates struct { - lat *LatitudeCode - - lng *LongitudeCode -} - -// Latitude returns the location's latitude. -func (c *Coordinates) Latitude() *LatitudeCode { - return c.lat -} - -// Longitude returns the location's longitude. -func (c *Coordinates) Longitude() *LongitudeCode { - return c.lng -} - -// CoordinatesFromString parses a string and returns the location's coordinates. -func CoordinatesFromString(s string) (*Coordinates, error) { - if len(s) == 0 { - return nil, nil - } - - strs := strings.Split(s, " ") - if len(strs) != 2 { - return nil, locode.ErrInvalidString - } - - lat, err := LatitudeFromString(strs[0]) - if err != nil { - return nil, fmt.Errorf("could not parse latitude: %w", err) - } - - lng, err := LongitudeFromString(strs[1]) - if err != nil { - return nil, fmt.Errorf("could not parse longitude: %w", err) - } - - return &Coordinates{ - lat: lat, - lng: lng, - }, nil -} diff --git a/pkg/util/locode/column/country.go b/pkg/util/locode/column/country.go deleted file mode 100644 index d407495b43..0000000000 --- a/pkg/util/locode/column/country.go +++ /dev/null @@ -1,38 +0,0 @@ -package locodecolumn - -import ( - "fmt" - - "github.com/nspcc-dev/neofs-node/pkg/util/locode" -) - -const countryCodeLen = 2 - -// CountryCode represents ISO 3166 alpha-2 Country Code. -type CountryCode [countryCodeLen]uint8 - -// Symbols returns digits of the country code. -func (cc *CountryCode) Symbols() [countryCodeLen]uint8 { - return *cc -} - -// CountryCodeFromString parses a string and returns the country code. -func CountryCodeFromString(s string) (*CountryCode, error) { - if l := len(s); l != countryCodeLen { - return nil, fmt.Errorf("incorrect country code length: expect: %d, got: %d", - countryCodeLen, - l, - ) - } - - for i := range s { - if !isUpperAlpha(s[i]) { - return nil, locode.ErrInvalidString - } - } - - cc := CountryCode{} - copy(cc[:], s) - - return &cc, nil -} diff --git a/pkg/util/locode/column/location.go b/pkg/util/locode/column/location.go deleted file mode 100644 index c9b38d49be..0000000000 --- a/pkg/util/locode/column/location.go +++ /dev/null @@ -1,38 +0,0 @@ -package locodecolumn - -import ( - "fmt" - - "github.com/nspcc-dev/neofs-node/pkg/util/locode" -) - -const locationCodeLen = 3 - -// LocationCode represents 3-character code for the location. -type LocationCode [locationCodeLen]uint8 - -// Symbols returns characters of the location code. -func (lc *LocationCode) Symbols() [locationCodeLen]uint8 { - return *lc -} - -// LocationCodeFromString parses a string and returns the location code. -func LocationCodeFromString(s string) (*LocationCode, error) { - if l := len(s); l != locationCodeLen { - return nil, fmt.Errorf("incorrect location code length: expect: %d, got: %d", - locationCodeLen, - l, - ) - } - - for i := range s { - if !isUpperAlpha(s[i]) && !isDigit(s[i]) { - return nil, locode.ErrInvalidString - } - } - - lc := LocationCode{} - copy(lc[:], s) - - return &lc, nil -} diff --git a/pkg/util/locode/column/util.go b/pkg/util/locode/column/util.go deleted file mode 100644 index 8da1f9a257..0000000000 --- a/pkg/util/locode/column/util.go +++ /dev/null @@ -1,9 +0,0 @@ -package locodecolumn - -func isDigit(sym uint8) bool { - return sym >= '0' && sym <= '9' -} - -func isUpperAlpha(sym uint8) bool { - return sym >= 'A' && sym <= 'Z' -} diff --git a/pkg/util/locode/db/airports/calls.go b/pkg/util/locode/db/airports/calls.go deleted file mode 100644 index d3f681f0d2..0000000000 --- a/pkg/util/locode/db/airports/calls.go +++ /dev/null @@ -1,194 +0,0 @@ -package airportsdb - -import ( - "encoding/csv" - "errors" - "fmt" - "io" - "os" - "strconv" - - "github.com/nspcc-dev/neofs-node/pkg/util/locode" - locodedb "github.com/nspcc-dev/neofs-node/pkg/util/locode/db" -) - -const ( - _ = iota - 1 - - _ // Airport ID - _ // Name - airportCity - airportCountry - airportIATA - _ // ICAO - airportLatitude - airportLongitude - _ // Altitude - _ // Timezone - _ // DST - _ // Tz database time zone - _ // Type - _ // Source - - airportFldNum -) - -type record struct { - city, - country, - iata, - lat, - lng string -} - -// Get scans the records of the OpenFlights Airport to an in-memory table (once), -// and returns an entry that matches the passed UN/LOCODE record. -// -// Records are matched if they have the same country code and either -// same IATA code or same city name (location name in UN/LOCODE). -// -// Returns locodedb.ErrAirportNotFound if no entry matches. -func (db *DB) Get(locodeRecord locode.Record) (*locodedb.AirportRecord, error) { - if err := db.initAirports(); err != nil { - return nil, err - } - - records := db.mAirports[locodeRecord.LOCODE.CountryCode()] - - for i := range records { - if locodeRecord.LOCODE.LocationCode() != records[i].iata && - locodeRecord.NameWoDiacritics != records[i].city { - continue - } - - lat, err := strconv.ParseFloat(records[i].lat, 64) - if err != nil { - return nil, err - } - - lng, err := strconv.ParseFloat(records[i].lng, 64) - if err != nil { - return nil, err - } - - return &locodedb.AirportRecord{ - CountryName: records[i].country, - Point: locodedb.NewPoint(lat, lng), - }, nil - } - - return nil, locodedb.ErrAirportNotFound -} - -const ( - _ = iota - 1 - - countryName - countryISOCode - _ // dafif_code - - countryFldNum -) - -// CountryName scans the records of the OpenFlights Country table to an in-memory table (once), -// and returns the name of the country by code. -// -// Returns locodedb.ErrCountryNotFound if no entry matches. -func (db *DB) CountryName(code *locodedb.CountryCode) (name string, err error) { - if err = db.initCountries(); err != nil { - return - } - - argCode := code.String() - - for cName, cCode := range db.mCountries { - if cCode == argCode { - name = cName - break - } - } - - if name == "" { - err = locodedb.ErrCountryNotFound - } - - return -} - -func (db *DB) initAirports() (err error) { - db.airportsOnce.Do(func() { - db.mAirports = make(map[string][]record) - - if err = db.initCountries(); err != nil { - return - } - - err = db.scanWords(db.airports, airportFldNum, func(words []string) error { - countryCode := db.mCountries[words[airportCountry]] - if countryCode != "" { - db.mAirports[countryCode] = append(db.mAirports[countryCode], record{ - city: words[airportCity], - country: words[airportCountry], - iata: words[airportIATA], - lat: words[airportLatitude], - lng: words[airportLongitude], - }) - } - - return nil - }) - }) - - return -} - -func (db *DB) initCountries() (err error) { - db.countriesOnce.Do(func() { - db.mCountries = make(map[string]string) - - err = db.scanWords(db.countries, countryFldNum, func(words []string) error { - db.mCountries[words[countryName]] = words[countryISOCode] - - return nil - }) - }) - - return -} - -var errScanInt = errors.New("interrupt scan") - -func (db *DB) scanWords(pm pathMode, num int, wordsHandler func([]string) error) error { - tableFile, err := os.OpenFile(pm.path, os.O_RDONLY, pm.mode) - if err != nil { - return err - } - - defer tableFile.Close() - - r := csv.NewReader(tableFile) - r.ReuseRecord = true - - for { - words, err := r.Read() - if err != nil { - if errors.Is(err, io.EOF) { - break - } - - return err - } else if ln := len(words); ln != num { - return fmt.Errorf("unexpected number of words %d", ln) - } - - if err := wordsHandler(words); err != nil { - if errors.Is(err, errScanInt) { - break - } - - return err - } - } - - return nil -} diff --git a/pkg/util/locode/db/airports/db.go b/pkg/util/locode/db/airports/db.go deleted file mode 100644 index acfa3fd607..0000000000 --- a/pkg/util/locode/db/airports/db.go +++ /dev/null @@ -1,83 +0,0 @@ -package airportsdb - -import ( - "fmt" - "io/fs" - "sync" -) - -// Prm groups the required parameters of the DB's constructor. -// -// All values must comply with the requirements imposed on them. -// Passing incorrect parameter values will result in constructor -// failure (error or panic depending on the implementation). -type Prm struct { - // Path to OpenFlights Airport csv table. - // - // Must not be empty. - AirportsPath string - - // Path to OpenFlights Countries csv table. - // - // Must not be empty. - CountriesPath string -} - -// DB is a descriptor of the OpenFlights database in csv format. -// -// For correct operation, DB must be created -// using the constructor (New) based on the required parameters -// and optional components. After successful creation, -// The DB is immediately ready to work through API. -type DB struct { - airports, countries pathMode - - airportsOnce, countriesOnce sync.Once - - mCountries map[string]string - - mAirports map[string][]record -} - -type pathMode struct { - path string - mode fs.FileMode -} - -const invalidPrmValFmt = "invalid parameter %s (%T):%v" - -func panicOnPrmValue(n string, v any) { - panic(fmt.Sprintf(invalidPrmValFmt, n, v, v)) -} - -// New creates a new instance of the DB. -// -// Panics if at least one value of the parameters is invalid. -// -// The created DB does not require additional -// initialization and is completely ready for work. -func New(prm Prm, opts ...Option) *DB { - switch { - case prm.AirportsPath == "": - panicOnPrmValue("AirportsPath", prm.AirportsPath) - case prm.CountriesPath == "": - panicOnPrmValue("CountriesPath", prm.CountriesPath) - } - - o := defaultOpts() - - for i := range opts { - opts[i](o) - } - - return &DB{ - airports: pathMode{ - path: prm.AirportsPath, - mode: o.airportMode, - }, - countries: pathMode{ - path: prm.CountriesPath, - mode: o.countryMode, - }, - } -} diff --git a/pkg/util/locode/db/airports/opts.go b/pkg/util/locode/db/airports/opts.go deleted file mode 100644 index 3799d9e270..0000000000 --- a/pkg/util/locode/db/airports/opts.go +++ /dev/null @@ -1,19 +0,0 @@ -package airportsdb - -import ( - "io/fs" -) - -// Option sets an optional parameter of DB. -type Option func(*options) - -type options struct { - airportMode, countryMode fs.FileMode -} - -func defaultOpts() *options { - return &options{ - airportMode: fs.ModePerm, // 0777 - countryMode: fs.ModePerm, // 0777 - } -} diff --git a/pkg/util/locode/db/boltdb/calls.go b/pkg/util/locode/db/boltdb/calls.go deleted file mode 100644 index 25ff96ee21..0000000000 --- a/pkg/util/locode/db/boltdb/calls.go +++ /dev/null @@ -1,166 +0,0 @@ -package locodebolt - -import ( - "encoding/json" - "errors" - "fmt" - "path/filepath" - - "github.com/nspcc-dev/neofs-node/pkg/util" - locodedb "github.com/nspcc-dev/neofs-node/pkg/util/locode/db" - "go.etcd.io/bbolt" -) - -// Open opens an underlying BoltDB instance. -// -// Timeout of BoltDB opening is 3s (only for Linux or Darwin). -// -// Opens BoltDB in read-only mode if DB is read-only. -func (db *DB) Open() error { - // copy-paste from metabase: - // consider universal Open/Close for BoltDB wrappers - - err := util.MkdirAllX(filepath.Dir(db.path), db.mode) - if err != nil { - return fmt.Errorf("could not create dir for BoltDB: %w", err) - } - - db.bolt, err = bbolt.Open(db.path, db.mode, db.boltOpts) - if err != nil { - return fmt.Errorf("could not open BoltDB: %w", err) - } - - return nil -} - -// Close closes an underlying BoltDB instance. -// -// Must not be called before successful Open call. -func (db *DB) Close() error { - return db.bolt.Close() -} - -func countryBucketKey(cc *locodedb.CountryCode) ([]byte, error) { - return []byte(cc.String()), nil -} - -func locationBucketKey(lc *locodedb.LocationCode) ([]byte, error) { - return []byte(lc.String()), nil -} - -type recordJSON struct { - CountryName string - LocationName string - SubDivName string - SubDivCode string - Latitude float64 - Longitude float64 - Continent string -} - -func recordValue(r locodedb.Record) ([]byte, error) { - p := r.GeoPoint() - - rj := &recordJSON{ - CountryName: r.CountryName(), - LocationName: r.LocationName(), - SubDivName: r.SubDivName(), - SubDivCode: r.SubDivCode(), - Latitude: p.Latitude(), - Longitude: p.Longitude(), - Continent: r.Continent().String(), - } - - return json.Marshal(rj) -} - -func recordFromValue(data []byte) (*locodedb.Record, error) { - rj := new(recordJSON) - - if err := json.Unmarshal(data, rj); err != nil { - return nil, err - } - - r := new(locodedb.Record) - r.SetCountryName(rj.CountryName) - r.SetLocationName(rj.LocationName) - r.SetSubDivName(rj.SubDivName) - r.SetSubDivCode(rj.SubDivCode) - r.SetGeoPoint(locodedb.NewPoint(rj.Latitude, rj.Longitude)) - - cont := locodedb.ContinentFromString(rj.Continent) - r.SetContinent(&cont) - - return r, nil -} - -// Put saves the record by key in an underlying BoltDB instance. -// -// Country code from the key is used for allocating the 1st level buckets. -// Records are stored in country buckets by the location code from the key. -// The records are stored in internal binary JSON format. -// -// Must not be called before successful Open call. -// Must not be called in read-only mode: behavior is undefined. -func (db *DB) Put(key locodedb.Key, rec locodedb.Record) error { - return db.bolt.Update(func(tx *bbolt.Tx) error { - countryKey, err := countryBucketKey(key.CountryCode()) - if err != nil { - return err - } - - bktCountry, err := tx.CreateBucketIfNotExists(countryKey) - if err != nil { - return fmt.Errorf("could not create country bucket: %w", err) - } - - locationKey, err := locationBucketKey(key.LocationCode()) - if err != nil { - return err - } - - cont, err := recordValue(rec) - if err != nil { - return err - } - - return bktCountry.Put(locationKey, cont) - }) -} - -var errRecordNotFound = errors.New("record not found") - -// Get reads the record by key from underlying BoltDB instance. -// -// Returns an error if no record is presented by key in DB. -// -// Must not be called before successful Open call. -func (db *DB) Get(key locodedb.Key) (rec *locodedb.Record, err error) { - err = db.bolt.View(func(tx *bbolt.Tx) error { - countryKey, err := countryBucketKey(key.CountryCode()) - if err != nil { - return err - } - - bktCountry := tx.Bucket(countryKey) - if bktCountry == nil { - return errRecordNotFound - } - - locationKey, err := locationBucketKey(key.LocationCode()) - if err != nil { - return err - } - - data := bktCountry.Get(locationKey) - if data == nil { - return errRecordNotFound - } - - rec, err = recordFromValue(data) - - return err - }) - - return -} diff --git a/pkg/util/locode/db/boltdb/db.go b/pkg/util/locode/db/boltdb/db.go deleted file mode 100644 index 6106af2f3e..0000000000 --- a/pkg/util/locode/db/boltdb/db.go +++ /dev/null @@ -1,73 +0,0 @@ -package locodebolt - -import ( - "fmt" - "io/fs" - - "go.etcd.io/bbolt" -) - -// Prm groups the required parameters of the DB's constructor. -// -// All values must comply with the requirements imposed on them. -// Passing incorrect parameter values will result in constructor -// failure (error or panic depending on the implementation). -type Prm struct { - // Path to BoltDB file with NeoFS location database. - // - // Must not be empty. - Path string -} - -// DB is a descriptor of the NeoFS BoltDB location database. -// -// For correct operation, DB must be created -// using the constructor (New) based on the required parameters -// and optional components. -// -// After successful creation, -// DB must be opened through Open call. After successful opening, -// DB is ready to work through API (until Close call). -// -// Upon completion of work with the DB, it must be closed -// by Close method. -type DB struct { - path string - - mode fs.FileMode - - boltOpts *bbolt.Options - - bolt *bbolt.DB -} - -const invalidPrmValFmt = "invalid parameter %s (%T):%v" - -func panicOnPrmValue(n string, v any) { - panic(fmt.Sprintf(invalidPrmValFmt, n, v, v)) -} - -// New creates a new instance of the DB. -// -// Panics if at least one value of the parameters is invalid. -// -// The created DB requires calling the Open method in order -// to initialize required resources. -func New(prm Prm, opts ...Option) *DB { - switch { - case prm.Path == "": - panicOnPrmValue("Path", prm.Path) - } - - o := defaultOpts() - - for i := range opts { - opts[i](o) - } - - return &DB{ - path: prm.Path, - mode: o.mode, - boltOpts: o.boltOpts, - } -} diff --git a/pkg/util/locode/db/boltdb/opts.go b/pkg/util/locode/db/boltdb/opts.go deleted file mode 100644 index db0cccd3a0..0000000000 --- a/pkg/util/locode/db/boltdb/opts.go +++ /dev/null @@ -1,37 +0,0 @@ -package locodebolt - -import ( - "io/fs" - "os" - "time" - - "go.etcd.io/bbolt" -) - -// Option sets an optional parameter of DB. -type Option func(*options) - -type options struct { - mode fs.FileMode - - boltOpts *bbolt.Options -} - -func defaultOpts() *options { - return &options{ - mode: os.ModePerm, // 0777 - boltOpts: &bbolt.Options{ - Timeout: 3 * time.Second, - }, - } -} - -// ReadOnly enables read-only mode of the DB. -// -// Do not call DB.Put method on instances with -// this option: the behavior is undefined. -func ReadOnly() Option { - return func(o *options) { - o.boltOpts.ReadOnly = true - } -} diff --git a/pkg/util/locode/db/continent.go b/pkg/util/locode/db/continent.go deleted file mode 100644 index 863af7b571..0000000000 --- a/pkg/util/locode/db/continent.go +++ /dev/null @@ -1,81 +0,0 @@ -package locodedb - -// Continent is an enumeration of Earth's continent. -type Continent uint8 - -const ( - // ContinentUnknown is an undefined Continent value. - ContinentUnknown = iota - - // ContinentEurope corresponds to Europe. - ContinentEurope - - // ContinentAfrica corresponds to Africa. - ContinentAfrica - - // ContinentNorthAmerica corresponds to North America. - ContinentNorthAmerica - - // ContinentSouthAmerica corresponds to South America. - ContinentSouthAmerica - - // ContinentAsia corresponds to Asia. - ContinentAsia - - // ContinentAntarctica corresponds to Antarctica. - ContinentAntarctica - - // ContinentOceania corresponds to Oceania. - ContinentOceania -) - -// Is checks if c is the same continent as c2. -func (c *Continent) Is(c2 Continent) bool { - return *c == c2 -} - -func (c Continent) String() string { - switch c { - case ContinentUnknown: - fallthrough - default: - return "Unknown" - case ContinentEurope: - return "Europe" - case ContinentAfrica: - return "Africa" - case ContinentNorthAmerica: - return "North America" - case ContinentSouthAmerica: - return "South America" - case ContinentAsia: - return "Asia" - case ContinentAntarctica: - return "Antarctica" - case ContinentOceania: - return "Oceania" - } -} - -// ContinentFromString returns Continent value -// corresponding to the passed string representation. -func ContinentFromString(str string) Continent { - switch str { - default: - return ContinentUnknown - case "Europe": - return ContinentEurope - case "Africa": - return ContinentAfrica - case "North America": - return ContinentNorthAmerica - case "South America": - return ContinentSouthAmerica - case "Asia": - return ContinentAsia - case "Antarctica": - return ContinentAntarctica - case "Oceania": - return ContinentOceania - } -} diff --git a/pkg/util/locode/db/continents/geojson/calls.go b/pkg/util/locode/db/continents/geojson/calls.go deleted file mode 100644 index a8351b745d..0000000000 --- a/pkg/util/locode/db/continents/geojson/calls.go +++ /dev/null @@ -1,98 +0,0 @@ -package continentsdb - -import ( - "fmt" - "os" - - locodedb "github.com/nspcc-dev/neofs-node/pkg/util/locode/db" - "github.com/paulmach/orb" - "github.com/paulmach/orb/geojson" - "github.com/paulmach/orb/planar" -) - -const continentProperty = "Continent" - -// PointContinent goes through all polygons and returns the continent -// in which the point is located. -// -// Returns locodedb.ContinentUnknown if no entry matches. -// -// All GeoJSON feature are parsed from file once and stored in memory. -func (db *DB) PointContinent(point *locodedb.Point) (*locodedb.Continent, error) { - var err error - - db.once.Do(func() { - err = db.init() - }) - - if err != nil { - return nil, err - } - - planarPoint := orb.Point{point.Longitude(), point.Latitude()} - - var ( - continent string - minDst float64 - ) - - for _, feature := range db.features { - if multiPolygon, ok := feature.Geometry.(orb.MultiPolygon); ok { - if planar.MultiPolygonContains(multiPolygon, planarPoint) { - continent = feature.Properties.MustString(continentProperty) - break - } - } else if polygon, ok := feature.Geometry.(orb.Polygon); ok { - if planar.PolygonContains(polygon, planarPoint) { - continent = feature.Properties.MustString(continentProperty) - break - } - } - distance := planar.DistanceFrom(feature.Geometry, planarPoint) - if minDst == 0 || minDst > distance { - minDst = distance - continent = feature.Properties.MustString(continentProperty) - } - } - - c := continentFromString(continent) - - return &c, nil -} - -func (db *DB) init() error { - data, err := os.ReadFile(db.path) - if err != nil { - return fmt.Errorf("could not read data file: %w", err) - } - - features, err := geojson.UnmarshalFeatureCollection(data) - if err != nil { - return fmt.Errorf("could not unmarshal GeoJSON feature collection: %w", err) - } - - db.features = features.Features - - return nil -} - -func continentFromString(c string) locodedb.Continent { - switch c { - default: - return locodedb.ContinentUnknown - case "Africa": - return locodedb.ContinentAfrica - case "Asia": - return locodedb.ContinentAsia - case "Europe": - return locodedb.ContinentEurope - case "North America": - return locodedb.ContinentNorthAmerica - case "South America": - return locodedb.ContinentSouthAmerica - case "Antarctica": - return locodedb.ContinentAntarctica - case "Australia", "Oceania": - return locodedb.ContinentOceania - } -} diff --git a/pkg/util/locode/db/continents/geojson/db.go b/pkg/util/locode/db/continents/geojson/db.go deleted file mode 100644 index ee43bd8108..0000000000 --- a/pkg/util/locode/db/continents/geojson/db.go +++ /dev/null @@ -1,63 +0,0 @@ -package continentsdb - -import ( - "fmt" - "sync" - - "github.com/paulmach/orb/geojson" -) - -// Prm groups the required parameters of the DB's constructor. -// -// All values must comply with the requirements imposed on them. -// Passing incorrect parameter values will result in constructor -// failure (error or panic depending on the implementation). -type Prm struct { - // Path to polygons of Earth's continents in GeoJSON format. - // - // Must not be empty. - Path string -} - -// DB is a descriptor of the Earth's polygons in GeoJSON format. -// -// For correct operation, DB must be created -// using the constructor (New) based on the required parameters -// and optional components. After successful creation, -// The DB is immediately ready to work through API. -type DB struct { - path string - - once sync.Once - - features []*geojson.Feature -} - -const invalidPrmValFmt = "invalid parameter %s (%T):%v" - -func panicOnPrmValue(n string, v any) { - panic(fmt.Sprintf(invalidPrmValFmt, n, v, v)) -} - -// New creates a new instance of the DB. -// -// Panics if at least one value of the parameters is invalid. -// -// The created DB does not require additional -// initialization and is completely ready for work. -func New(prm Prm, opts ...Option) *DB { - switch { - case prm.Path == "": - panicOnPrmValue("Path", prm.Path) - } - - o := defaultOpts() - - for i := range opts { - opts[i](o) - } - - return &DB{ - path: prm.Path, - } -} diff --git a/pkg/util/locode/db/continents/geojson/opts.go b/pkg/util/locode/db/continents/geojson/opts.go deleted file mode 100644 index 59831fcc5f..0000000000 --- a/pkg/util/locode/db/continents/geojson/opts.go +++ /dev/null @@ -1,10 +0,0 @@ -package continentsdb - -// Option sets an optional parameter of DB. -type Option func(*options) - -type options struct{} - -func defaultOpts() *options { - return &options{} -} diff --git a/pkg/util/locode/db/country.go b/pkg/util/locode/db/country.go deleted file mode 100644 index ab64127733..0000000000 --- a/pkg/util/locode/db/country.go +++ /dev/null @@ -1,32 +0,0 @@ -package locodedb - -import ( - "fmt" - - locodecolumn "github.com/nspcc-dev/neofs-node/pkg/util/locode/column" -) - -// CountryCode represents a country code for -// the storage in the NeoFS location database. -type CountryCode locodecolumn.CountryCode - -// CountryCodeFromString parses a string UN/LOCODE country code -// and returns a CountryCode. -func CountryCodeFromString(s string) (*CountryCode, error) { - cc, err := locodecolumn.CountryCodeFromString(s) - if err != nil { - return nil, fmt.Errorf("could not parse country code: %w", err) - } - - return CountryFromColumn(cc) -} - -// CountryFromColumn converts a UN/LOCODE country code to a CountryCode. -func CountryFromColumn(cc *locodecolumn.CountryCode) (*CountryCode, error) { - return (*CountryCode)(cc), nil -} - -func (c *CountryCode) String() string { - syms := (*locodecolumn.CountryCode)(c).Symbols() - return string(syms[:]) -} diff --git a/pkg/util/locode/db/db.go b/pkg/util/locode/db/db.go deleted file mode 100644 index 623c05e8af..0000000000 --- a/pkg/util/locode/db/db.go +++ /dev/null @@ -1,169 +0,0 @@ -package locodedb - -import ( - "errors" - "fmt" - - "github.com/nspcc-dev/neofs-node/pkg/util/locode" -) - -// SourceTable is an interface of the UN/LOCODE table. -type SourceTable interface { - // Must iterate over all entries of the table - // and pass next entry to the handler. - // - // Must return handler's errors directly. - IterateAll(func(locode.Record) error) error -} - -// DB is an interface of NeoFS location database. -type DB interface { - // Must save the record by key in the database. - Put(Key, Record) error - - // Must return the record by key from the database. - Get(Key) (*Record, error) -} - -// AirportRecord represents the entry in NeoFS airport database. -type AirportRecord struct { - // Name of the country where airport is located. - CountryName string - - // Geo point where airport is located. - Point *Point -} - -// ErrAirportNotFound is returned by AirportRecord readers -// when the required airport is not found. -var ErrAirportNotFound = errors.New("airport not found") - -// AirportDB is an interface of NeoFS airport database. -type AirportDB interface { - // Must return the record by UN/LOCODE table record. - // - // Must return ErrAirportNotFound if there is no - // related airport in the database. - Get(locode.Record) (*AirportRecord, error) -} - -// ContinentsDB is an interface of NeoFS continent database. -type ContinentsDB interface { - // Must return continent of the geo point. - PointContinent(*Point) (*Continent, error) -} - -var ErrSubDivNotFound = errors.New("subdivision not found") - -var ErrCountryNotFound = errors.New("country not found") - -// NamesDB is an interface of the NeoFS location namespace. -type NamesDB interface { - // Must resolve a country code to a country name. - // - // Must return ErrCountryNotFound if there is no - // country with the provided code. - CountryName(*CountryCode) (string, error) - - // Must resolve (country code, subdivision code) to - // a subdivision name. - // - // Must return ErrSubDivNotFound if either country or - // subdivision is not presented in database. - SubDivName(*CountryCode, string) (string, error) -} - -// FillDatabase generates the NeoFS location database based on the UN/LOCODE table. -func FillDatabase(table SourceTable, airports AirportDB, continents ContinentsDB, names NamesDB, db DB) error { - return table.IterateAll(func(tableRecord locode.Record) error { - if tableRecord.LOCODE.LocationCode() == "" { - return nil - } - - dbKey, err := NewKey(tableRecord.LOCODE) - if err != nil { - return err - } - - dbRecord, err := NewRecord(tableRecord) - if err != nil { - if errors.Is(err, errParseCoordinates) { - return nil - } - - return err - } - - geoPoint := dbRecord.GeoPoint() - countryName := "" - - if geoPoint == nil { - airportRecord, err := airports.Get(tableRecord) - if err != nil { - if errors.Is(err, ErrAirportNotFound) { - return nil - } - - return err - } - - geoPoint = airportRecord.Point - countryName = airportRecord.CountryName - } - - dbRecord.SetGeoPoint(geoPoint) - - if countryName == "" { - countryName, err = names.CountryName(dbKey.CountryCode()) - if err != nil { - if errors.Is(err, ErrCountryNotFound) { - return nil - } - - return err - } - } - - dbRecord.SetCountryName(countryName) - - if subDivCode := dbRecord.SubDivCode(); subDivCode != "" { - subDivName, err := names.SubDivName(dbKey.CountryCode(), subDivCode) - if err != nil { - if errors.Is(err, ErrSubDivNotFound) { - return nil - } - - return err - } - - dbRecord.SetSubDivName(subDivName) - } - - continent, err := continents.PointContinent(geoPoint) - if err != nil { - return fmt.Errorf("could not calculate continent geo point: %w", err) - } else if continent.Is(ContinentUnknown) { - return nil - } - - dbRecord.SetContinent(continent) - - return db.Put(*dbKey, *dbRecord) - }) -} - -// LocodeRecord returns the record from the NeoFS location database -// corresponding to the string representation of UN/LOCODE. -func LocodeRecord(db DB, sLocode string) (*Record, error) { - lc, err := locode.FromString(sLocode) - if err != nil { - return nil, fmt.Errorf("could not parse locode: %w", err) - } - - key, err := NewKey(*lc) - if err != nil { - return nil, err - } - - return db.Get(*key) -} diff --git a/pkg/util/locode/db/location.go b/pkg/util/locode/db/location.go deleted file mode 100644 index 5f6862315e..0000000000 --- a/pkg/util/locode/db/location.go +++ /dev/null @@ -1,32 +0,0 @@ -package locodedb - -import ( - "fmt" - - locodecolumn "github.com/nspcc-dev/neofs-node/pkg/util/locode/column" -) - -// LocationCode represents a location code for -// the storage in the NeoFS location database. -type LocationCode locodecolumn.LocationCode - -// LocationCodeFromString parses a string UN/LOCODE location code -// and returns a LocationCode. -func LocationCodeFromString(s string) (*LocationCode, error) { - lc, err := locodecolumn.LocationCodeFromString(s) - if err != nil { - return nil, fmt.Errorf("could not parse location code: %w", err) - } - - return LocationFromColumn(lc) -} - -// LocationFromColumn converts a UN/LOCODE country code to a LocationCode. -func LocationFromColumn(cc *locodecolumn.LocationCode) (*LocationCode, error) { - return (*LocationCode)(cc), nil -} - -func (l *LocationCode) String() string { - syms := (*locodecolumn.LocationCode)(l).Symbols() - return string(syms[:]) -} diff --git a/pkg/util/locode/db/point.go b/pkg/util/locode/db/point.go deleted file mode 100644 index 7a2879c9f8..0000000000 --- a/pkg/util/locode/db/point.go +++ /dev/null @@ -1,93 +0,0 @@ -package locodedb - -import ( - "fmt" - "strconv" - - locodecolumn "github.com/nspcc-dev/neofs-node/pkg/util/locode/column" -) - -// Point represents a 2D geographic point. -type Point struct { - lat, lng float64 -} - -// NewPoint creates, initializes and returns a new Point. -func NewPoint(lat, lng float64) *Point { - return &Point{ - lat: lat, - lng: lng, - } -} - -// Latitude returns the Point's latitude. -func (p Point) Latitude() float64 { - return p.lat -} - -// Longitude returns the Point's longitude. -func (p Point) Longitude() float64 { - return p.lng -} - -// PointFromCoordinates converts a UN/LOCODE coordinates to a Point. -func PointFromCoordinates(crd *locodecolumn.Coordinates) (*Point, error) { - if crd == nil { - return nil, nil - } - - cLat := crd.Latitude() - cLatDeg := cLat.Degrees() - cLatMnt := cLat.Minutes() - - lat, err := toDecimal(cLatDeg[:], cLatMnt[:]) - if err != nil { - return nil, fmt.Errorf("could not parse latitude: %w", err) - } - - if !cLat.Hemisphere().North() { - lat = -lat - } - - cLng := crd.Longitude() - cLngDeg := cLng.Degrees() - cLngMnt := cLng.Minutes() - - lng, err := toDecimal(cLngDeg[:], cLngMnt[:]) - if err != nil { - return nil, fmt.Errorf("could not parse longitude: %w", err) - } - - if !cLng.Hemisphere().East() { - lng = -lng - } - - return &Point{ - lat: lat, - lng: lng, - }, nil -} - -func toDecimal(intRaw, minutesRaw []byte) (float64, error) { - integer, err := strconv.ParseFloat(string(intRaw), 64) - if err != nil { - return 0, fmt.Errorf("could not parse integer part: %w", err) - } - - decimal, err := minutesToDegrees(minutesRaw) - if err != nil { - return 0, fmt.Errorf("could not parse decimal part: %w", err) - } - - return integer + decimal, nil -} - -// minutesToDegrees converts minutes to decimal part of a degree. -func minutesToDegrees(raw []byte) (float64, error) { - minutes, err := strconv.ParseFloat(string(raw), 64) - if err != nil { - return 0, err - } - - return minutes / 60, nil -} diff --git a/pkg/util/locode/db/point_test.go b/pkg/util/locode/db/point_test.go deleted file mode 100644 index b6f5c627ac..0000000000 --- a/pkg/util/locode/db/point_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package locodedb - -import ( - "testing" - - locodecolumn "github.com/nspcc-dev/neofs-node/pkg/util/locode/column" - "github.com/stretchr/testify/require" -) - -func TestPointFromCoordinates(t *testing.T) { - testCases := []struct { - latGot, longGot string - latWant, longWant float64 - }{ - { - latGot: "5915N", - longGot: "01806E", - latWant: 59.25, - longWant: 18.10, - }, - { - latGot: "1000N", - longGot: "02030E", - latWant: 10.00, - longWant: 20.50, - }, - { - latGot: "0145S", - longGot: "03512W", - latWant: -01.75, - longWant: -35.20, - }, - } - - var ( - crd *locodecolumn.Coordinates - point *Point - err error - ) - - for _, test := range testCases { - crd, err = locodecolumn.CoordinatesFromString(test.latGot + " " + test.longGot) - require.NoError(t, err) - - point, err = PointFromCoordinates(crd) - require.NoError(t, err) - - require.Equal(t, test.latWant, point.Latitude()) - require.Equal(t, test.longWant, point.Longitude()) - } -} diff --git a/pkg/util/locode/db/record.go b/pkg/util/locode/db/record.go deleted file mode 100644 index 367de4ce09..0000000000 --- a/pkg/util/locode/db/record.go +++ /dev/null @@ -1,140 +0,0 @@ -package locodedb - -import ( - "errors" - "fmt" - - "github.com/nspcc-dev/neofs-node/pkg/util/locode" - locodecolumn "github.com/nspcc-dev/neofs-node/pkg/util/locode/column" -) - -// Key represents the key in NeoFS location database. -type Key struct { - cc *CountryCode - - lc *LocationCode -} - -// NewKey calculates Key from LOCODE. -func NewKey(lc locode.LOCODE) (*Key, error) { - country, err := CountryCodeFromString(lc.CountryCode()) - if err != nil { - return nil, fmt.Errorf("could not parse country: %w", err) - } - - location, err := LocationCodeFromString(lc.LocationCode()) - if err != nil { - return nil, fmt.Errorf("could not parse location: %w", err) - } - - return &Key{ - cc: country, - lc: location, - }, nil -} - -// CountryCode returns the location's country code. -func (k *Key) CountryCode() *CountryCode { - return k.cc -} - -// LocationCode returns the location code. -func (k *Key) LocationCode() *LocationCode { - return k.lc -} - -// Record represents the entry in NeoFS location database. -type Record struct { - countryName string - - locationName string - - subDivName string - - subDivCode string - - p *Point - - cont *Continent -} - -var errParseCoordinates = errors.New("invalid coordinates") - -// NewRecord calculates the Record from the UN/LOCODE table record. -func NewRecord(r locode.Record) (*Record, error) { - crd, err := locodecolumn.CoordinatesFromString(r.Coordinates) - if err != nil { - return nil, fmt.Errorf("%w: %v", errParseCoordinates, err) - } - - point, err := PointFromCoordinates(crd) - if err != nil { - return nil, fmt.Errorf("could not parse geo point: %w", err) - } - - return &Record{ - locationName: r.NameWoDiacritics, - subDivCode: r.SubDiv, - p: point, - }, nil -} - -// CountryName returns the country name. -func (r *Record) CountryName() string { - return r.countryName -} - -// SetCountryName sets the country name. -func (r *Record) SetCountryName(name string) { - r.countryName = name -} - -// LocationName returns the location name. -func (r *Record) LocationName() string { - return r.locationName -} - -// SetLocationName sets the location name. -func (r *Record) SetLocationName(name string) { - r.locationName = name -} - -// SubDivCode returns the subdivision code. -func (r *Record) SubDivCode() string { - return r.subDivCode -} - -// SetSubDivCode sets the subdivision code. -func (r *Record) SetSubDivCode(name string) { - r.subDivCode = name -} - -// SubDivName returns the subdivision name. -func (r *Record) SubDivName() string { - return r.subDivName -} - -// SetSubDivName sets the subdivision name. -func (r *Record) SetSubDivName(name string) { - r.subDivName = name -} - -// GeoPoint returns geo point of the location. -func (r *Record) GeoPoint() *Point { - return r.p -} - -// SetGeoPoint sets geo point of the location. -func (r *Record) SetGeoPoint(p *Point) { - r.p = p -} - -// Continent returns the location continent. -func (r *Record) Continent() *Continent { - return r.cont -} - -// SetContinent sets the location continent. -func (r *Record) SetContinent(c *Continent) { - r.cont = c -} diff --git a/pkg/util/locode/record.go b/pkg/util/locode/record.go deleted file mode 100644 index 7db746ff3b..0000000000 --- a/pkg/util/locode/record.go +++ /dev/null @@ -1,83 +0,0 @@ -package locode - -import ( - "errors" - "fmt" - "strings" -) - -// LOCODE represents code from UN/LOCODE coding scheme. -type LOCODE [2]string - -// Record represents a single record of the UN/LOCODE table. -type Record struct { - // Change Indicator. - Ch string - - // Combination of a 2-character country code and a 3-character location code. - LOCODE LOCODE - - // Name of the locations which has been allocated a UN/LOCODE. - Name string - - // Names of the locations which have been allocated a UN/LOCODE without diacritic signs. - NameWoDiacritics string - - // ISO 1-3 character alphabetic and/or numeric code for the administrative division of the country concerned. - SubDiv string - - // 8-digit function classifier code for the location. - Function string - - // Status of the entry by a 2-character code. - Status string - - // Last date when the location was updated/entered. - Date string - - // The IATA code for the location if different from location code in column LOCODE. - IATA string - - // Geographical coordinates (latitude/longitude) of the location, if there is any. - Coordinates string - - // Some general remarks regarding the UN/LOCODE in question. - Remarks string -} - -// ErrInvalidString is the error of incorrect string format of the LOCODE. -var ErrInvalidString = errors.New("invalid string format in UN/Locode") - -// FromString parses string and returns LOCODE. -// -// If string has incorrect format, ErrInvalidString returns. -func FromString(s string) (*LOCODE, error) { - const ( - locationSeparator = " " - locodePartsNumber = 2 - ) - - words := strings.Split(s, locationSeparator) - if ln := len(words); ln != locodePartsNumber { - return nil, fmt.Errorf( - "incorrect locode: it must consist of %d codes separated with a witespase, got: %d", - locodePartsNumber, - ln, - ) - } - - l := new(LOCODE) - copy(l[:], words) - - return l, nil -} - -// CountryCode returns a string representation of country code. -func (l *LOCODE) CountryCode() string { - return l[0] -} - -// LocationCode returns a string representation of location code. -func (l *LOCODE) LocationCode() string { - return l[1] -} diff --git a/pkg/util/locode/table/csv/calls.go b/pkg/util/locode/table/csv/calls.go deleted file mode 100644 index 159fa5e2ec..0000000000 --- a/pkg/util/locode/table/csv/calls.go +++ /dev/null @@ -1,156 +0,0 @@ -package csvlocode - -import ( - "encoding/csv" - "errors" - "io" - "os" - "strings" - - "github.com/nspcc-dev/neofs-node/pkg/util/locode" - locodedb "github.com/nspcc-dev/neofs-node/pkg/util/locode/db" -) - -var errInvalidRecord = errors.New("invalid table record") - -// IterateAll scans a table record one-by-one, parses a UN/LOCODE record -// from it and passes it to f. -// -// Returns f's errors directly. -func (t *Table) IterateAll(f func(locode.Record) error) error { - const wordsPerRecord = 12 - - return t.scanWords(t.paths, wordsPerRecord, func(words []string) error { - lc, err := locode.FromString(strings.Join(words[1:3], " ")) - if err != nil { - return err - } - - record := locode.Record{ - Ch: words[0], - LOCODE: *lc, - Name: words[3], - NameWoDiacritics: words[4], - SubDiv: words[5], - Function: words[6], - Status: words[7], - Date: words[8], - IATA: words[9], - Coordinates: words[10], - Remarks: words[11], - } - - return f(record) - }) -} - -const ( - _ = iota - 1 - - subDivCountry - subDivSubdivision - subDivName - _ // subDivLevel - - subDivFldNum -) - -type subDivKey struct { - countryCode, - subDivCode string -} - -type subDivRecord struct { - name string -} - -// SubDivName scans a table record to an in-memory table (once), -// and returns the subdivision name of the country and the subdivision codes match. -// -// Returns locodedb.ErrSubDivNotFound if no entry matches. -func (t *Table) SubDivName(countryCode *locodedb.CountryCode, code string) (string, error) { - if err := t.initSubDiv(); err != nil { - return "", err - } - - rec, ok := t.mSubDiv[subDivKey{ - countryCode: countryCode.String(), - subDivCode: code, - }] - if !ok { - return "", locodedb.ErrSubDivNotFound - } - - return rec.name, nil -} - -func (t *Table) initSubDiv() (err error) { - t.subDivOnce.Do(func() { - t.mSubDiv = make(map[subDivKey]subDivRecord) - - err = t.scanWords([]string{t.subDivPath}, subDivFldNum, func(words []string) error { - t.mSubDiv[subDivKey{ - countryCode: words[subDivCountry], - subDivCode: words[subDivSubdivision], - }] = subDivRecord{ - name: words[subDivName], - } - - return nil - }) - }) - - return -} - -var errScanInt = errors.New("interrupt scan") - -func (t *Table) scanWords(paths []string, fpr int, wordsHandler func([]string) error) error { - var ( - rdrs = make([]io.Reader, 0, len(t.paths)) - closers = make([]io.Closer, 0, len(t.paths)) - ) - - for i := range paths { - file, err := os.OpenFile(paths[i], os.O_RDONLY, t.mode) - if err != nil { - return err - } - - rdrs = append(rdrs, file) - closers = append(closers, file) - } - - defer func() { - for i := range closers { - _ = closers[i].Close() - } - }() - - r := csv.NewReader(io.MultiReader(rdrs...)) - r.ReuseRecord = true - r.FieldsPerRecord = fpr - - for { - words, err := r.Read() - if err != nil { - if errors.Is(err, io.EOF) { - break - } - - return err - } else if len(words) != fpr { - return errInvalidRecord - } - - if err := wordsHandler(words); err != nil { - if errors.Is(err, errScanInt) { - break - } - - return err - } - } - - return nil -} diff --git a/pkg/util/locode/table/csv/opts.go b/pkg/util/locode/table/csv/opts.go deleted file mode 100644 index 5aaffd7c17..0000000000 --- a/pkg/util/locode/table/csv/opts.go +++ /dev/null @@ -1,28 +0,0 @@ -package csvlocode - -import ( - "io/fs" -) - -// Option sets an optional parameter of Table. -type Option func(*options) - -type options struct { - mode fs.FileMode - - extraPaths []string -} - -func defaultOpts() *options { - return &options{ - mode: 0700, - } -} - -// WithExtraPaths returns an option to add extra paths -// to UN/LOCODE tables in csv format. -func WithExtraPaths(ps ...string) Option { - return func(o *options) { - o.extraPaths = append(o.extraPaths, ps...) - } -} diff --git a/pkg/util/locode/table/csv/table.go b/pkg/util/locode/table/csv/table.go deleted file mode 100644 index b84c2b705e..0000000000 --- a/pkg/util/locode/table/csv/table.go +++ /dev/null @@ -1,75 +0,0 @@ -package csvlocode - -import ( - "fmt" - "io/fs" - "sync" -) - -// Prm groups the required parameters of the Table's constructor. -// -// All values must comply with the requirements imposed on them. -// Passing incorrect parameter values will result in constructor -// failure (error or panic depending on the implementation). -type Prm struct { - // Path to UN/LOCODE csv table. - // - // Must not be empty. - Path string - - // Path to csv table of UN/LOCODE Subdivisions. - // - // Must not be empty. - SubDivPath string -} - -// Table is a descriptor of the UN/LOCODE table in csv format. -// -// For correct operation, Table must be created -// using the constructor (New) based on the required parameters -// and optional components. After successful creation, -// The Table is immediately ready to work through API. -type Table struct { - paths []string - - mode fs.FileMode - - subDivPath string - - subDivOnce sync.Once - - mSubDiv map[subDivKey]subDivRecord -} - -const invalidPrmValFmt = "invalid parameter %s (%T):%v" - -func panicOnPrmValue(n string, v any) { - panic(fmt.Sprintf(invalidPrmValFmt, n, v, v)) -} - -// New creates a new instance of the Table. -// -// Panics if at least one value of the parameters is invalid. -// -// The created Table does not require additional -// initialization and is completely ready for work. -func New(prm Prm, opts ...Option) *Table { - switch { - case prm.Path == "": - panicOnPrmValue("Path", prm.Path) - case prm.SubDivPath == "": - panicOnPrmValue("SubDivPath", prm.SubDivPath) - } - - o := defaultOpts() - - for i := range opts { - opts[i](o) - } - - return &Table{ - paths: append(o.extraPaths, prm.Path), - mode: o.mode, - subDivPath: prm.SubDivPath, - } -}