From 6ce73790ea89556327cc77d10ad49f5722aefe9e Mon Sep 17 00:00:00 2001 From: Pavel Pogodaev Date: Mon, 7 Oct 2024 17:20:25 +0300 Subject: [PATCH] [#276] Merge repo with frostfs-api-go Signed-off-by: Pavel Pogodaev --- .gitattributes | 3 + Makefile | 65 + accounting/decimal.go | 4 +- accounting/decimal_test.go | 2 +- accounting/doc.go | 2 +- ape/chain.go | 2 +- ape/chain_target.go | 2 +- ape/chain_target_test.go | 2 +- ape/chain_test.go | 2 +- ape/grpc/types_frostfs.pb.go | Bin 0 -> 8595 bytes ape/grpc/types_frostfs_fuzz.go | 45 + ape/grpc/types_frostfs_test.go | 31 + api/accounting/accounting.go | 104 + api/accounting/convert.go | 178 ++ api/accounting/grpc/service_frostfs.pb.go | Bin 0 -> 18911 bytes api/accounting/grpc/service_frostfs_fuzz.go | 45 + api/accounting/grpc/service_frostfs_test.go | 31 + api/accounting/grpc/service_grpc.pb.go | Bin 0 -> 4333 bytes api/accounting/grpc/types_frostfs.pb.go | Bin 0 -> 4327 bytes api/accounting/grpc/types_frostfs_fuzz.go | 26 + api/accounting/grpc/types_frostfs_test.go | 21 + api/accounting/json.go | 14 + api/accounting/marshal.go | 104 + api/accounting/message_test.go | 19 + api/accounting/test/generate.go | 64 + api/acl/bench_test.go | 51 + api/acl/convert.go | 592 ++++ api/acl/filters.go | 33 + api/acl/grpc/types_frostfs.pb.go | Bin 0 -> 48134 bytes api/acl/grpc/types_frostfs_fuzz.go | 64 + api/acl/grpc/types_frostfs_test.go | 41 + api/acl/json.go | 70 + api/acl/marshal.go | 350 +++ api/acl/message_test.go | 21 + api/acl/string.go | 110 + api/acl/test/generate.go | 144 + api/acl/types.go | 426 +++ api/ape/convert.go | 132 + api/ape/grpc/types_frostfs.pb.go | Bin 0 -> 8671 bytes api/ape/grpc/types_frostfs_fuzz.go | 45 + api/ape/grpc/types_frostfs_test.go | 31 + api/ape/json.go | 14 + api/ape/marshal.go | 92 + api/ape/message_test.go | 15 + api/ape/string.go | 18 + api/ape/test/generate.go | 71 + api/ape/types.go | 79 + api/apemanager/convert.go | 358 +++ api/apemanager/grpc/service_frostfs.pb.go | Bin 0 -> 57305 bytes api/apemanager/grpc/service_frostfs_fuzz.go | 121 + api/apemanager/grpc/service_frostfs_test.go | 71 + api/apemanager/grpc/service_grpc.pb.go | Bin 0 -> 9917 bytes api/apemanager/marshal.go | 205 ++ api/apemanager/message_test.go | 26 + api/apemanager/status.go | 76 + api/apemanager/status_test.go | 30 + api/apemanager/test/generate.go | 143 + api/apemanager/types.go | 226 ++ api/container/attributes.go | 90 + api/container/attributes_test.go | 59 + api/container/convert.go | 764 +++++ api/container/grpc/service_frostfs.pb.go | Bin 0 -> 76792 bytes api/container/grpc/service_frostfs_fuzz.go | 159 + api/container/grpc/service_frostfs_test.go | 91 + api/container/grpc/service_grpc.pb.go | Bin 0 -> 11737 bytes api/container/grpc/types_frostfs.pb.go | Bin 0 -> 12289 bytes api/container/grpc/types_frostfs_fuzz.go | 26 + api/container/grpc/types_frostfs_test.go | 21 + api/container/json.go | 22 + api/container/marshal.go | 345 +++ api/container/message_test.go | 36 + api/container/status.go | 33 + api/container/status_test.go | 15 + api/container/test/generate.go | 240 ++ api/container/types.go | 446 +++ api/lock/grpc/types_frostfs.pb.go | Bin 0 -> 3858 bytes api/lock/grpc/types_frostfs_fuzz.go | 26 + api/lock/grpc/types_frostfs_test.go | 21 + api/netmap/convert.go | 916 ++++++ api/netmap/grpc/service_frostfs.pb.go | Bin 0 -> 55007 bytes api/netmap/grpc/service_frostfs_fuzz.go | 121 + api/netmap/grpc/service_frostfs_test.go | 71 + api/netmap/grpc/service_grpc.pb.go | Bin 0 -> 9148 bytes api/netmap/grpc/types_frostfs.pb.go | Bin 0 -> 57653 bytes api/netmap/grpc/types_frostfs_fuzz.go | 159 + api/netmap/grpc/types_frostfs_test.go | 91 + api/netmap/json.go | 62 + api/netmap/marshal.go | 576 ++++ api/netmap/message_test.go | 32 + api/netmap/string.go | 68 + api/netmap/test/generate.go | 335 +++ api/netmap/types.go | 783 +++++ api/object/attributes.go | 187 ++ api/object/attributes_test.go | 89 + api/object/bench_test.go | 45 + api/object/convert.go | 2555 +++++++++++++++++ api/object/filters.go | 58 + api/object/grpc/service_frostfs.pb.go | Bin 0 -> 224187 bytes api/object/grpc/service_frostfs_fuzz.go | 387 +++ api/object/grpc/service_frostfs_test.go | 211 ++ api/object/grpc/service_grpc.pb.go | Bin 0 -> 45844 bytes api/object/grpc/types_frostfs.pb.go | Bin 0 -> 65533 bytes api/object/grpc/types_frostfs_fuzz.go | 102 + api/object/grpc/types_frostfs_test.go | 61 + api/object/json.go | 94 + api/object/lock.go | 160 ++ api/object/lock_test.go | 26 + api/object/marshal.go | 1428 +++++++++ api/object/message_test.go | 65 + api/object/status.go | 91 + api/object/status_test.go | 35 + api/object/string.go | 55 + api/object/test/generate.go | 766 +++++ api/object/types.go | 1650 +++++++++++ api/refs/bench_test.go | 53 + api/refs/convert.go | 264 ++ api/refs/grpc/types_frostfs.pb.go | Bin 0 -> 31179 bytes api/refs/grpc/types_frostfs_fuzz.go | 159 + api/refs/grpc/types_frostfs_test.go | 91 + api/refs/json.go | 62 + api/refs/marshal.go | 264 ++ api/refs/message_test.go | 21 + api/refs/string.go | 47 + api/refs/test/generate.go | 127 + api/refs/types.go | 194 ++ api/rpc/accounting.go | 29 + api/rpc/apemanager.go | 60 + api/rpc/client/call_options.go | 40 + api/rpc/client/client.go | 30 + api/rpc/client/conn.go | 24 + api/rpc/client/connect.go | 72 + api/rpc/client/flows.go | 124 + api/rpc/client/init.go | 69 + api/rpc/client/options.go | 129 + api/rpc/client/options_test.go | 197 ++ api/rpc/client/stream_wrapper.go | 58 + api/rpc/client/util.go | 13 + api/rpc/common.go | 10 + api/rpc/common/call.go | 75 + api/rpc/common/call_test.go | 49 + api/rpc/container.go | 82 + api/rpc/grpc/init.go | 4 + api/rpc/message/encoding.go | 40 + api/rpc/message/message.go | 43 + api/rpc/message/test/message.go | 126 + api/rpc/netmap.go | 62 + api/rpc/object.go | 243 ++ api/rpc/session.go | 28 + api/session/convert.go | 898 ++++++ api/session/grpc/service_frostfs.pb.go | Bin 0 -> 20352 bytes api/session/grpc/service_frostfs_fuzz.go | 45 + api/session/grpc/service_frostfs_test.go | 31 + api/session/grpc/service_grpc.pb.go | Bin 0 -> 4116 bytes api/session/grpc/types_frostfs.pb.go | Bin 0 -> 70892 bytes api/session/grpc/types_frostfs_fuzz.go | 159 + api/session/grpc/types_frostfs_test.go | 91 + api/session/json.go | 86 + api/session/marshal.go | 536 ++++ api/session/message_test.go | 27 + api/session/status.go | 32 + api/session/status_test.go | 15 + api/session/string.go | 47 + api/session/test/generate.go | 251 ++ api/session/types.go | 836 ++++++ api/session/util.go | 167 ++ api/session/xheaders.go | 34 + api/signature/body.go | 116 + api/signature/marshaller.go | 26 + api/signature/sign.go | 122 + api/signature/sign_test.go | 125 + api/signature/verify.go | 127 + api/status/convert.go | 95 + api/status/details.go | 8 + api/status/grpc/types_frostfs.pb.go | Bin 0 -> 14223 bytes api/status/grpc/types_frostfs_fuzz.go | 26 + api/status/grpc/types_frostfs_test.go | 21 + api/status/marshal.go | 92 + api/status/message_test.go | 16 + api/status/status.go | 103 + api/status/test/codes.go | 28 + api/status/test/generate.go | 44 + api/status/types.go | 124 + api/tombstone/convert.go | 41 + api/tombstone/grpc/types_frostfs.pb.go | Bin 0 -> 5846 bytes api/tombstone/grpc/types_frostfs_fuzz.go | 26 + api/tombstone/grpc/types_frostfs_test.go | 21 + api/tombstone/json.go | 14 + api/tombstone/marshal.go | 56 + api/tombstone/message_test.go | 15 + api/tombstone/test/generate.go | 23 + api/tombstone/types.go | 57 + api/util/pool/buffer.go | 54 + api/util/pool/marshal.go | 7 + api/util/proto/encoding/compat.go | 22 + api/util/proto/encoding/json.go | 48 + api/util/proto/encoding/proto.go | 57 + api/util/proto/marshal.go | 413 +++ api/util/proto/marshal_test.go | 247 ++ api/util/proto/test/custom/test_frostfs.pb.go | Bin 0 -> 35040 bytes api/util/proto/test/test.pb.go | Bin 0 -> 20911 bytes api/util/protogen/internalgengo/file.go | 245 ++ api/util/protogen/internalgengo/fuzz.go | 69 + api/util/protogen/internalgengo/getter.go | 14 + api/util/protogen/internalgengo/json.go | 284 ++ api/util/protogen/internalgengo/options.go | 7 + api/util/protogen/internalgengo/proto.go | 202 ++ .../internalgengo/proto_field_type.go | 59 + .../internalgengo/proto_stable_compat.go | 124 + api/util/protogen/internalgengo/writer.go | 30 + api/util/protogen/main.go | 27 + api/util/signature/data.go | 93 + api/util/signature/options.go | 77 + api/util/signature/sign_test.go | 44 + api/util/signature/walletconnect/sign.go | 142 + api/util/signature/walletconnect/sign_test.go | 112 + bearer/bearer.go | 8 +- bearer/bearer_test.go | 4 +- checksum/checksum.go | 4 +- checksum/checksum_test.go | 2 +- checksum/example_test.go | 2 +- client/accounting.go | 12 +- client/apemanager_add_chain.go | 10 +- client/apemanager_list_chains.go | 10 +- client/apemanager_remove_chain.go | 10 +- client/api.go | 6 +- client/client.go | 8 +- client/common.go | 12 +- client/container_delete.go | 12 +- client/container_get.go | 12 +- client/container_list.go | 12 +- client/container_put.go | 12 +- client/doc.go | 4 +- client/netmap.go | 10 +- client/netmap_test.go | 6 +- client/object_delete.go | 14 +- client/object_get.go | 14 +- client/object_hash.go | 14 +- client/object_patch.go | 12 +- client/object_patch_test.go | 2 +- client/object_put.go | 2 +- client/object_put_raw.go | 12 +- client/object_put_single.go | 12 +- client/object_put_transformer.go | 2 +- client/object_search.go | 14 +- client/object_search_test.go | 6 +- client/response.go | 2 +- client/session.go | 10 +- client/status/apemanager.go | 4 +- client/status/common.go | 6 +- client/status/common_test.go | 2 +- client/status/container.go | 4 +- client/status/object.go | 4 +- client/status/session.go | 4 +- client/status/success.go | 2 +- client/status/unrecognized.go | 2 +- client/status/v2.go | 12 +- container/container.go | 8 +- container/container_test.go | 6 +- container/doc.go | 2 +- container/id/id.go | 4 +- container/id/id_test.go | 2 +- crypto/crypto_test.go | 2 +- crypto/doc.go | 2 +- crypto/ecdsa/wallet_connect.go | 2 +- crypto/signature.go | 4 +- crypto/signer.go | 2 +- eacl/enums.go | 2 +- eacl/enums_test.go | 2 +- eacl/filter.go | 2 +- eacl/filter_test.go | 2 +- eacl/record.go | 2 +- eacl/record_test.go | 2 +- eacl/table.go | 4 +- eacl/table_test.go | 2 +- eacl/target.go | 2 +- eacl/target_test.go | 2 +- go.mod | 11 +- go.sum | Bin 17907 -> 17793 bytes netmap/context.go | 2 +- netmap/doc.go | 2 +- netmap/filter.go | 2 +- netmap/filter_test.go | 2 +- netmap/helper_test.go | 2 +- netmap/netmap.go | 4 +- netmap/netmap_test.go | 2 +- netmap/network_info.go | 4 +- netmap/network_info_test.go | 2 +- netmap/node_info.go | 4 +- netmap/node_info_test.go | 2 +- netmap/policy.go | 4 +- netmap/selector.go | 2 +- netmap/selector_test.go | 2 +- netmap/yml_unmarshal.go | 2 +- object/attribute.go | 2 +- object/attribute_test.go | 2 +- object/ecinfo.go | 4 +- object/erasure_code.go | 4 +- object/error_test.go | 4 +- object/fmt.go | 2 +- object/id/address.go | 4 +- object/id/address_test.go | 2 +- object/id/id.go | 4 +- object/id/id_test.go | 2 +- object/lock.go | 4 +- object/object.go | 8 +- object/object_test.go | 2 +- object/patch.go | 4 +- object/patch_test.go | 4 +- object/range.go | 2 +- object/range_test.go | 2 +- object/raw.go | 2 +- object/raw_test.go | 2 +- object/search.go | 2 +- object/search_test.go | 2 +- object/splitinfo.go | 4 +- object/splitinfo_test.go | 2 +- object/tombstone.go | 4 +- object/tombstone_test.go | 2 +- object/transformer/transformer.go | 2 +- object/type.go | 2 +- object/type_test.go | 2 +- pool/mock_test.go | 2 +- pool/tree/client.go | 2 +- pool/tree/service/service_frostfs.pb.go | Bin 60583 -> 60584 bytes pool/tree/service/types_frostfs.pb.go | Bin 3111 -> 3112 bytes prepare.sh | 39 + session/common.go | 4 +- session/container.go | 6 +- session/container_test.go | 4 +- session/doc.go | 2 +- session/object.go | 6 +- session/object_test.go | 4 +- user/doc.go | 2 +- user/id.go | 4 +- user/id_test.go | 2 +- version/version.go | 4 +- version/version_test.go | 2 +- 337 files changed, 28244 insertions(+), 279 deletions(-) create mode 100644 ape/grpc/types_frostfs.pb.go create mode 100644 ape/grpc/types_frostfs_fuzz.go create mode 100644 ape/grpc/types_frostfs_test.go create mode 100644 api/accounting/accounting.go create mode 100644 api/accounting/convert.go create mode 100644 api/accounting/grpc/service_frostfs.pb.go create mode 100644 api/accounting/grpc/service_frostfs_fuzz.go create mode 100644 api/accounting/grpc/service_frostfs_test.go create mode 100644 api/accounting/grpc/service_grpc.pb.go create mode 100644 api/accounting/grpc/types_frostfs.pb.go create mode 100644 api/accounting/grpc/types_frostfs_fuzz.go create mode 100644 api/accounting/grpc/types_frostfs_test.go create mode 100644 api/accounting/json.go create mode 100644 api/accounting/marshal.go create mode 100644 api/accounting/message_test.go create mode 100644 api/accounting/test/generate.go create mode 100644 api/acl/bench_test.go create mode 100644 api/acl/convert.go create mode 100644 api/acl/filters.go create mode 100644 api/acl/grpc/types_frostfs.pb.go create mode 100644 api/acl/grpc/types_frostfs_fuzz.go create mode 100644 api/acl/grpc/types_frostfs_test.go create mode 100644 api/acl/json.go create mode 100644 api/acl/marshal.go create mode 100644 api/acl/message_test.go create mode 100644 api/acl/string.go create mode 100644 api/acl/test/generate.go create mode 100644 api/acl/types.go create mode 100644 api/ape/convert.go create mode 100644 api/ape/grpc/types_frostfs.pb.go create mode 100644 api/ape/grpc/types_frostfs_fuzz.go create mode 100644 api/ape/grpc/types_frostfs_test.go create mode 100644 api/ape/json.go create mode 100644 api/ape/marshal.go create mode 100644 api/ape/message_test.go create mode 100644 api/ape/string.go create mode 100644 api/ape/test/generate.go create mode 100644 api/ape/types.go create mode 100644 api/apemanager/convert.go create mode 100644 api/apemanager/grpc/service_frostfs.pb.go create mode 100644 api/apemanager/grpc/service_frostfs_fuzz.go create mode 100644 api/apemanager/grpc/service_frostfs_test.go create mode 100644 api/apemanager/grpc/service_grpc.pb.go create mode 100644 api/apemanager/marshal.go create mode 100644 api/apemanager/message_test.go create mode 100644 api/apemanager/status.go create mode 100644 api/apemanager/status_test.go create mode 100644 api/apemanager/test/generate.go create mode 100644 api/apemanager/types.go create mode 100644 api/container/attributes.go create mode 100644 api/container/attributes_test.go create mode 100644 api/container/convert.go create mode 100644 api/container/grpc/service_frostfs.pb.go create mode 100644 api/container/grpc/service_frostfs_fuzz.go create mode 100644 api/container/grpc/service_frostfs_test.go create mode 100644 api/container/grpc/service_grpc.pb.go create mode 100644 api/container/grpc/types_frostfs.pb.go create mode 100644 api/container/grpc/types_frostfs_fuzz.go create mode 100644 api/container/grpc/types_frostfs_test.go create mode 100644 api/container/json.go create mode 100644 api/container/marshal.go create mode 100644 api/container/message_test.go create mode 100644 api/container/status.go create mode 100644 api/container/status_test.go create mode 100644 api/container/test/generate.go create mode 100644 api/container/types.go create mode 100644 api/lock/grpc/types_frostfs.pb.go create mode 100644 api/lock/grpc/types_frostfs_fuzz.go create mode 100644 api/lock/grpc/types_frostfs_test.go create mode 100644 api/netmap/convert.go create mode 100644 api/netmap/grpc/service_frostfs.pb.go create mode 100644 api/netmap/grpc/service_frostfs_fuzz.go create mode 100644 api/netmap/grpc/service_frostfs_test.go create mode 100644 api/netmap/grpc/service_grpc.pb.go create mode 100644 api/netmap/grpc/types_frostfs.pb.go create mode 100644 api/netmap/grpc/types_frostfs_fuzz.go create mode 100644 api/netmap/grpc/types_frostfs_test.go create mode 100644 api/netmap/json.go create mode 100644 api/netmap/marshal.go create mode 100644 api/netmap/message_test.go create mode 100644 api/netmap/string.go create mode 100644 api/netmap/test/generate.go create mode 100644 api/netmap/types.go create mode 100644 api/object/attributes.go create mode 100644 api/object/attributes_test.go create mode 100644 api/object/bench_test.go create mode 100644 api/object/convert.go create mode 100644 api/object/filters.go create mode 100644 api/object/grpc/service_frostfs.pb.go create mode 100644 api/object/grpc/service_frostfs_fuzz.go create mode 100644 api/object/grpc/service_frostfs_test.go create mode 100644 api/object/grpc/service_grpc.pb.go create mode 100644 api/object/grpc/types_frostfs.pb.go create mode 100644 api/object/grpc/types_frostfs_fuzz.go create mode 100644 api/object/grpc/types_frostfs_test.go create mode 100644 api/object/json.go create mode 100644 api/object/lock.go create mode 100644 api/object/lock_test.go create mode 100644 api/object/marshal.go create mode 100644 api/object/message_test.go create mode 100644 api/object/status.go create mode 100644 api/object/status_test.go create mode 100644 api/object/string.go create mode 100644 api/object/test/generate.go create mode 100644 api/object/types.go create mode 100644 api/refs/bench_test.go create mode 100644 api/refs/convert.go create mode 100644 api/refs/grpc/types_frostfs.pb.go create mode 100644 api/refs/grpc/types_frostfs_fuzz.go create mode 100644 api/refs/grpc/types_frostfs_test.go create mode 100644 api/refs/json.go create mode 100644 api/refs/marshal.go create mode 100644 api/refs/message_test.go create mode 100644 api/refs/string.go create mode 100644 api/refs/test/generate.go create mode 100644 api/refs/types.go create mode 100644 api/rpc/accounting.go create mode 100644 api/rpc/apemanager.go create mode 100644 api/rpc/client/call_options.go create mode 100644 api/rpc/client/client.go create mode 100644 api/rpc/client/conn.go create mode 100644 api/rpc/client/connect.go create mode 100644 api/rpc/client/flows.go create mode 100644 api/rpc/client/init.go create mode 100644 api/rpc/client/options.go create mode 100644 api/rpc/client/options_test.go create mode 100644 api/rpc/client/stream_wrapper.go create mode 100644 api/rpc/client/util.go create mode 100644 api/rpc/common.go create mode 100644 api/rpc/common/call.go create mode 100644 api/rpc/common/call_test.go create mode 100644 api/rpc/container.go create mode 100644 api/rpc/grpc/init.go create mode 100644 api/rpc/message/encoding.go create mode 100644 api/rpc/message/message.go create mode 100644 api/rpc/message/test/message.go create mode 100644 api/rpc/netmap.go create mode 100644 api/rpc/object.go create mode 100644 api/rpc/session.go create mode 100644 api/session/convert.go create mode 100644 api/session/grpc/service_frostfs.pb.go create mode 100644 api/session/grpc/service_frostfs_fuzz.go create mode 100644 api/session/grpc/service_frostfs_test.go create mode 100644 api/session/grpc/service_grpc.pb.go create mode 100644 api/session/grpc/types_frostfs.pb.go create mode 100644 api/session/grpc/types_frostfs_fuzz.go create mode 100644 api/session/grpc/types_frostfs_test.go create mode 100644 api/session/json.go create mode 100644 api/session/marshal.go create mode 100644 api/session/message_test.go create mode 100644 api/session/status.go create mode 100644 api/session/status_test.go create mode 100644 api/session/string.go create mode 100644 api/session/test/generate.go create mode 100644 api/session/types.go create mode 100644 api/session/util.go create mode 100644 api/session/xheaders.go create mode 100644 api/signature/body.go create mode 100644 api/signature/marshaller.go create mode 100644 api/signature/sign.go create mode 100644 api/signature/sign_test.go create mode 100644 api/signature/verify.go create mode 100644 api/status/convert.go create mode 100644 api/status/details.go create mode 100644 api/status/grpc/types_frostfs.pb.go create mode 100644 api/status/grpc/types_frostfs_fuzz.go create mode 100644 api/status/grpc/types_frostfs_test.go create mode 100644 api/status/marshal.go create mode 100644 api/status/message_test.go create mode 100644 api/status/status.go create mode 100644 api/status/test/codes.go create mode 100644 api/status/test/generate.go create mode 100644 api/status/types.go create mode 100644 api/tombstone/convert.go create mode 100644 api/tombstone/grpc/types_frostfs.pb.go create mode 100644 api/tombstone/grpc/types_frostfs_fuzz.go create mode 100644 api/tombstone/grpc/types_frostfs_test.go create mode 100644 api/tombstone/json.go create mode 100644 api/tombstone/marshal.go create mode 100644 api/tombstone/message_test.go create mode 100644 api/tombstone/test/generate.go create mode 100644 api/tombstone/types.go create mode 100644 api/util/pool/buffer.go create mode 100644 api/util/pool/marshal.go create mode 100644 api/util/proto/encoding/compat.go create mode 100644 api/util/proto/encoding/json.go create mode 100644 api/util/proto/encoding/proto.go create mode 100644 api/util/proto/marshal.go create mode 100644 api/util/proto/marshal_test.go create mode 100644 api/util/proto/test/custom/test_frostfs.pb.go create mode 100644 api/util/proto/test/test.pb.go create mode 100644 api/util/protogen/internalgengo/file.go create mode 100644 api/util/protogen/internalgengo/fuzz.go create mode 100644 api/util/protogen/internalgengo/getter.go create mode 100644 api/util/protogen/internalgengo/json.go create mode 100644 api/util/protogen/internalgengo/options.go create mode 100644 api/util/protogen/internalgengo/proto.go create mode 100644 api/util/protogen/internalgengo/proto_field_type.go create mode 100644 api/util/protogen/internalgengo/proto_stable_compat.go create mode 100644 api/util/protogen/internalgengo/writer.go create mode 100644 api/util/protogen/main.go create mode 100644 api/util/signature/data.go create mode 100644 api/util/signature/options.go create mode 100644 api/util/signature/sign_test.go create mode 100644 api/util/signature/walletconnect/sign.go create mode 100644 api/util/signature/walletconnect/sign_test.go create mode 100755 prepare.sh diff --git a/.gitattributes b/.gitattributes index b371347..f7ff250 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,3 +2,6 @@ /pkg/policy/parser/generate.go diff **/*.interp -diff **/*.tokens -diff +/**/*.pb.go -diff -merge +/**/*.pb.go linguist-generated=true +/go.sum -diff diff --git a/Makefile b/Makefile index 32b588e..6f62f6d 100755 --- a/Makefile +++ b/Makefile @@ -7,11 +7,76 @@ TRUECLOUDLAB_LINT_VERSION ?= 0.0.6 OUTPUT_LINT_DIR ?= $(shell pwd)/bin LINT_DIR = $(OUTPUT_LINT_DIR)/golangci-lint-$(LINT_VERSION)-v$(TRUECLOUDLAB_LINT_VERSION) +PROTOC_VERSION ?= 27.2 +PROTOC_GEN_GO_VERSION ?= $(shell go list -f '{{.Version}}' -m google.golang.org/protobuf) +PROTOC_OS_VERSION=osx-x86_64 +ifeq ($(shell uname), Linux) + PROTOC_OS_VERSION=linux-x86_64 +endif + +BIN = bin +PROTOBUF_DIR ?= $(abspath $(BIN))/protobuf +PROTOC_DIR ?= $(PROTOBUF_DIR)/protoc-v$(PROTOC_VERSION) +PROTOC_GEN_GO_DIR ?= $(PROTOBUF_DIR)/protoc-gen-go-$(PROTOC_GEN_GO_VERSION) + + +.PHONY: dep imports protoc test lint help $(BIN)/protogen protoc-test + # Run tests test: GOFLAGS ?= "-cover -count=1" test: @GOFLAGS=$(GOFLAGS) go test ./... +# Reformat imports +imports: + @echo "⇒ Processing goimports check" + @for f in `find . -type f -name '*.go' -not -name '*.pb.go' -prune`; do \ + goimports -w $$f; \ + done + +# Install protoc +protoc-install: + @rm -rf $(PROTOBUF_DIR) + @mkdir -p $(PROTOBUF_DIR) + @echo "⇒ Installing protoc... " + @wget -q -O $(PROTOBUF_DIR)/protoc-$(PROTOC_VERSION).zip 'https://github.com/protocolbuffers/protobuf/releases/download/v$(PROTOC_VERSION)/protoc-$(PROTOC_VERSION)-$(PROTOC_OS_VERSION).zip' + @unzip -q -o $(PROTOBUF_DIR)/protoc-$(PROTOC_VERSION).zip -d $(PROTOC_DIR) + @rm $(PROTOBUF_DIR)/protoc-$(PROTOC_VERSION).zip + @echo "⇒ Installing protoc-gen-go..." + @GOBIN=$(PROTOC_GEN_GO_DIR) go install -v google.golang.org/protobuf/...@$(PROTOC_GEN_GO_VERSION) + + +# Regenerate code for proto files +protoc: + @if [ ! -d "$(PROTOC_DIR)" ] || [ ! -d "$(PROTOC_GEN_GO_DIR)" ]; then \ + make protoc-install; \ + fi + # Protoc generate + @for f in `find . -type f -name '*.proto' -not -path './bin/*' -not -path './api/util/proto/test/*'`; do \ + echo "⇒ Processing $$f "; \ + $(PROTOC_DIR)/bin/protoc \ + --proto_path=.:$(PROTOC_DIR)/include:/usr/local/include \ + --plugin=protoc-gen-go-frostfs=$(abspath ./bin/protogen) \ + --go-frostfs_out=fuzz=true:. \ + --go-frostfs_opt=paths=source_relative \ + --go-grpc_opt=require_unimplemented_servers=false \ + --go-grpc_out=. --go-grpc_opt=paths=source_relative $$f; \ + done + +$(BIN)/protogen: + @go build -v -trimpath \ + -o $(BIN)/protogen \ + ./api/util/protogen + +protoc-test: protoc $(BIN)/protogen + @$(PROTOC_DIR)/bin/protoc \ + --go_out=. --go_opt=paths=source_relative \ + --plugin=protoc-gen-go-frostfs=$(abspath $(BIN)/protogen) \ + --go-frostfs_opt=Mapi/util/proto/test/test.proto=git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/util/proto/test/custom \ + --go-frostfs_opt=module=git.frostfs.info/TrueCloudLab/frostfs-sdk-go \ + --go-frostfs_out=. --go-frostfs_opt=paths=import \ + ./api/util/proto/test/test.proto + # Pull go dependencies dep: @printf "⇒ Download requirements: " diff --git a/accounting/decimal.go b/accounting/decimal.go index bb01f28..b6d7386 100644 --- a/accounting/decimal.go +++ b/accounting/decimal.go @@ -1,10 +1,10 @@ package accounting -import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting" +import "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/accounting" // Decimal represents decimal number for accounting operations. // -// Decimal is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting.Decimal +// Decimal is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/accounting.Decimal // message. See ReadFromV2 / WriteToV2 methods. // // Instances can be created using built-in var declaration. diff --git a/accounting/decimal_test.go b/accounting/decimal_test.go index af46dd4..cdc6b69 100644 --- a/accounting/decimal_test.go +++ b/accounting/decimal_test.go @@ -3,8 +3,8 @@ package accounting_test import ( "testing" - v2accounting "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/accounting" + v2accounting "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/accounting" "github.com/stretchr/testify/require" ) diff --git a/accounting/doc.go b/accounting/doc.go index defcb0d..d5a9bfb 100644 --- a/accounting/doc.go +++ b/accounting/doc.go @@ -13,7 +13,7 @@ Instances can be also used to process FrostFS API V2 protocol messages On client side: - import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting" + import "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/accounting" var msg accounting.Decimal dec.WriteToV2(&msg) diff --git a/ape/chain.go b/ape/chain.go index eae441d..5a5548d 100644 --- a/ape/chain.go +++ b/ape/chain.go @@ -4,7 +4,7 @@ import ( "errors" "fmt" - apeV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/ape" + apeV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape" ) var ( diff --git a/ape/chain_target.go b/ape/chain_target.go index 13b7e87..cb63db7 100644 --- a/ape/chain_target.go +++ b/ape/chain_target.go @@ -1,7 +1,7 @@ package ape import ( - apeV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/ape" + apeV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape" ) // TargetType is an SDK representation for v2's TargetType. diff --git a/ape/chain_target_test.go b/ape/chain_target_test.go index 21a11b7..e7416d1 100644 --- a/ape/chain_target_test.go +++ b/ape/chain_target_test.go @@ -6,7 +6,7 @@ import ( "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape" "github.com/stretchr/testify/require" - apeV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/ape" + apeV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape" ) var ( diff --git a/ape/chain_test.go b/ape/chain_test.go index 83991f6..4e47fc6 100644 --- a/ape/chain_test.go +++ b/ape/chain_test.go @@ -6,7 +6,7 @@ import ( "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape" "github.com/stretchr/testify/require" - apeV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/ape" + apeV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape" ) const ( diff --git a/ape/grpc/types_frostfs.pb.go b/ape/grpc/types_frostfs.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..c16e8673897c7071da1cb3c81841ec2663f0ef70 GIT binary patch literal 8595 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 literal 0 HcmV?d00001 diff --git a/ape/grpc/types_frostfs_fuzz.go b/ape/grpc/types_frostfs_fuzz.go new file mode 100644 index 0000000..b7bf367 --- /dev/null +++ b/ape/grpc/types_frostfs_fuzz.go @@ -0,0 +1,45 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package ape + +func DoFuzzProtoChainTarget(data []byte) int { + msg := new(ChainTarget) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONChainTarget(data []byte) int { + msg := new(ChainTarget) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoChain(data []byte) int { + msg := new(Chain) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONChain(data []byte) int { + msg := new(Chain) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} diff --git a/ape/grpc/types_frostfs_test.go b/ape/grpc/types_frostfs_test.go new file mode 100644 index 0000000..93d7eea --- /dev/null +++ b/ape/grpc/types_frostfs_test.go @@ -0,0 +1,31 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package ape + +import ( + testing "testing" +) + +func FuzzProtoChainTarget(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoChainTarget(data) + }) +} +func FuzzJSONChainTarget(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONChainTarget(data) + }) +} +func FuzzProtoChain(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoChain(data) + }) +} +func FuzzJSONChain(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONChain(data) + }) +} diff --git a/api/accounting/accounting.go b/api/accounting/accounting.go new file mode 100644 index 0000000..04603cd --- /dev/null +++ b/api/accounting/accounting.go @@ -0,0 +1,104 @@ +package accounting + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" +) + +type BalanceRequestBody struct { + ownerID *refs.OwnerID +} + +type BalanceResponseBody struct { + bal *Decimal +} + +type Decimal struct { + val int64 + + prec uint32 +} + +type BalanceRequest struct { + body *BalanceRequestBody + + session.RequestHeaders +} + +type BalanceResponse struct { + body *BalanceResponseBody + + session.ResponseHeaders +} + +func (b *BalanceRequestBody) GetOwnerID() *refs.OwnerID { + if b != nil { + return b.ownerID + } + + return nil +} + +func (b *BalanceRequestBody) SetOwnerID(v *refs.OwnerID) { + b.ownerID = v +} + +func (b *BalanceRequest) GetBody() *BalanceRequestBody { + if b != nil { + return b.body + } + + return nil +} + +func (b *BalanceRequest) SetBody(v *BalanceRequestBody) { + b.body = v +} + +func (d *Decimal) GetValue() int64 { + if d != nil { + return d.val + } + + return 0 +} + +func (d *Decimal) SetValue(v int64) { + d.val = v +} + +func (d *Decimal) GetPrecision() uint32 { + if d != nil { + return d.prec + } + + return 0 +} + +func (d *Decimal) SetPrecision(v uint32) { + d.prec = v +} + +func (br *BalanceResponseBody) GetBalance() *Decimal { + if br != nil { + return br.bal + } + + return nil +} + +func (br *BalanceResponseBody) SetBalance(v *Decimal) { + br.bal = v +} + +func (br *BalanceResponse) GetBody() *BalanceResponseBody { + if br != nil { + return br.body + } + + return nil +} + +func (br *BalanceResponse) SetBody(v *BalanceResponseBody) { + br.body = v +} diff --git a/api/accounting/convert.go b/api/accounting/convert.go new file mode 100644 index 0000000..53b7491 --- /dev/null +++ b/api/accounting/convert.go @@ -0,0 +1,178 @@ +package accounting + +import ( + accounting "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/accounting/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + refsGRPC "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" +) + +func (b *BalanceRequestBody) ToGRPCMessage() grpc.Message { + var m *accounting.BalanceRequest_Body + + if b != nil { + m = new(accounting.BalanceRequest_Body) + + m.SetOwnerId(b.ownerID.ToGRPCMessage().(*refsGRPC.OwnerID)) + } + + return m +} + +func (b *BalanceRequestBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*accounting.BalanceRequest_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + ownerID := v.GetOwnerId() + if ownerID == nil { + b.ownerID = nil + } else { + if b.ownerID == nil { + b.ownerID = new(refs.OwnerID) + } + + err = b.ownerID.FromGRPCMessage(ownerID) + } + + return err +} + +func (b *BalanceRequest) ToGRPCMessage() grpc.Message { + var m *accounting.BalanceRequest + + if b != nil { + m = new(accounting.BalanceRequest) + + m.SetBody(b.body.ToGRPCMessage().(*accounting.BalanceRequest_Body)) + b.RequestHeaders.ToMessage(m) + } + + return m +} + +func (b *BalanceRequest) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*accounting.BalanceRequest) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + b.body = nil + } else { + if b.body == nil { + b.body = new(BalanceRequestBody) + } + + err = b.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + return b.RequestHeaders.FromMessage(v) +} + +func (d *Decimal) ToGRPCMessage() grpc.Message { + var m *accounting.Decimal + + if d != nil { + m = new(accounting.Decimal) + + m.SetValue(d.val) + m.SetPrecision(d.prec) + } + + return m +} + +func (d *Decimal) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*accounting.Decimal) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + d.val = v.GetValue() + d.prec = v.GetPrecision() + + return nil +} + +func (br *BalanceResponseBody) ToGRPCMessage() grpc.Message { + var m *accounting.BalanceResponse_Body + + if br != nil { + m = new(accounting.BalanceResponse_Body) + + m.SetBalance(br.bal.ToGRPCMessage().(*accounting.Decimal)) + } + + return m +} + +func (br *BalanceResponseBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*accounting.BalanceResponse_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + bal := v.GetBalance() + if bal == nil { + br.bal = nil + } else { + if br.bal == nil { + br.bal = new(Decimal) + } + + err = br.bal.FromGRPCMessage(bal) + } + + return err +} + +func (br *BalanceResponse) ToGRPCMessage() grpc.Message { + var m *accounting.BalanceResponse + + if br != nil { + m = new(accounting.BalanceResponse) + + m.SetBody(br.body.ToGRPCMessage().(*accounting.BalanceResponse_Body)) + br.ResponseHeaders.ToMessage(m) + } + + return m +} + +func (br *BalanceResponse) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*accounting.BalanceResponse) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + br.body = nil + } else { + if br.body == nil { + br.body = new(BalanceResponseBody) + } + + err = br.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + return br.ResponseHeaders.FromMessage(v) +} diff --git a/api/accounting/grpc/service_frostfs.pb.go b/api/accounting/grpc/service_frostfs.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..86502ef365180ca33406b23220db44436cfff1ad GIT binary patch literal 18911 zcmeHOZFAek5&lg6iZf@DfT|3}_BVChnc8w2b!^LHImw5nlR)4>LW~y{07a=D{r5h* z_ksffzR9FyX_S#;6S%$I+qc_&v>c7Z>wGN5napGnRB|j%uf(Ltt2}&)XHU=ar%{oY zRaE-o@L0S*{v_TU9)0rr{Yemh4$hDU8%B#qTBejIq&WgBNwOFkg^oRX^ zbv2RVRgeT(C_l>oPGwpB{wg0|iLxrDVI{uwd&e_4;n7&^k%4{n=}`PZd=Cb>dO7%` zf8Fn21O<87@4_6{|3F%N7Zl}rkU%OSUJ7rogWb@};$+w+{W(i5@k&yX$ak56pZae- zQkR*bTp=(tI2wtQDmYE#N&G)43Rz8ytQ6I`6eT^#BXKF>OhxbMG!ju>q(S9_PLYzD zr-dxVEUwNKU64u<#WER-iy(nX#CdQb>sP0778I}$w)gwdGz*1yDLS?4NahWN#{$J! zH6*jfB-qQB0*a@PJtevLvERGy_ju)BUMi{m_wWiiK4Fi5s3&0TJ=+(T+8M?$oTer^ z@&qVF8-hK6&W$XT$W&&PQqCe5fq1frf^g;0=Jxl-WhMUopVO;K4)x!3tW+G}6vzj) zV|<`b|CE&nvBxrkTXwwvFs-~43oiXPXVg)>uY7sSRu&&K)WB|2~<>Y^+b_J);v{Yb)BAFe+GX zN4p$aUE7kD$nfyWBDA*jWKjtG$qPO><(McGwR-+Rf$}wJ%+!>dm|Atsc-XILJEUysY!B}M2LPsb<`@3?m zF9sc1Z2(15H1$fvc6d(AneqE+%5sH4DaEq`foRc57HfOspbGXy{+T=%6xu9@cuF42 z;y%G!idh@A9fD3x>ePZNDK#IKj75Wo>u1nTCTE_Tfv8oitN&) zmFz%#H-qZ1J2N6p;SYXvHbH8F8!itV1hSSN8LoLnnIz{JR&Q(%vMINdn%hN_8#|}n z7rMM?=D~lR9KWBBow*BZ?SRo~hPI@%uCgBMQ3uJ4tffl<|5vUEzCf*)CPBSH4Z_sl z&!Bm&l$rl(8X+CxuQ(aMLLx1_;l7xu2v}(dEtK6lpH^b8DMM%G!aDzBFvIPFlGGby z(9XKPt-z=jK-pUTGYE1GC{!cYqb&q z7T}TcyIz=QU^7868(&iW19@P_!EdI>`E7833d^w90;}b;y)}MI%a8>NV1R~D*APlw zl{T6dI*DCzqrA$drU11`6(NU22~BWZtLo8zOJ(L4N;C(8R{ zF|CTz_CCm*doE|?9p$Hd@>X8RgzOz>{!xkQs^H5S7Ul=<;Ue&RZS=UNV9R0&Zi8}~ z$}#6loT7(kC!ga9e|G!|j}K)Mr`n6??s&o+^ix=fxqOyaTAH7;GKi!~;;7O*b{{f6 z$bJp7>UEyv8MEmSwjoAMk)}Ga!~f8*k%x0;)|Un`r-SijVO()=fG6zsy&m6)&16I` zd(onV-izw|ZLJz-bPUIfK^@T((x29$I-!;q&uaaVFH;2083PMkTX0d)(Q!D<2KOGO z`0lD{%{%^EHzB8JSkQs=&^!e{;eO^$gYSZ8zHVw7uhbrzIJHEy#V@jmqbt2ha|?bI zhe3rdRWHz6TsTBu(FxtG396~)t`kR7?fz$u%0?%vPE#(V`ewVH;jSAVa!+{r>h|b4 zwMVtntwr;KXj}&bmCmzHU-c0VeiEN$a!i>T#a)t=f*LIDA4`72>6=?m>NCYrL<^|X zL1}!3E;BCiuaX+EAOp{OJ8tc8>7x)dBv>0HNe;i4W7D;M)Lm|nT~YOhyh-gG@FrOR ztD2q1D0as&>SPqmL_8A&InaGdeKFre06owTRx-I_5s&ern8l^sZ?w=_Y+My;Q%er1 zXv<1wMkd>yZqP|P+FIC2!>6pam3pYN;k%Qy0R5o`CCBiFevJh1mB<}_gW8^sT?pU+ zov2X23p#o-tI`jSOucNmrQTR7}Me#900PT_#z zJkoGqk$|DtHVD9%snh*j`t)SI_MdKZH-owDvHN_*ZqF5%pmuX}TXR46&59jg+!{PF z6!u!QZhilei48yr@)jxqDPivnksu}wID)-aVG$je3hu-nd6R`C*rnTsBAK^8K{GD}U?K+tkzx)|4B~JJ*%Vtf4LUMVG$#eWRXl z>CN3@cbY>dg&%#VF2%ft!j>AHfIn3wl(*gFYVT?l&1-W4)I}5?aIUT}Bv$G^fo=)w zS^(3r$hH3&kgmgPmkM9+uz|90gqn^HLfB>pXYTUdOKpuKxvtSVRNJ+d9?sosv*Wpx ztpm2D&Z6OGyOT4upC|i{=_H_3krIp759>C%r3O;#?I9&-&@;%uB(jw_0 zClJDf%&{v3HMJniN;&I@U5umdSlSB*&siz28%&EOz9r<>DOv9n^mXL00r!aaHt@AkCy>=Z*-8|sRisahD`tfWF*m*g@?>XfBxQ;fx*gKSAoCb-R)Hzi{ zJ~zXs9ac4R+#KPsEg0&926EgnAT-yk?s|IzeU{IJ>kyLYvls)X5ADxu<{&! zH~*{Zrmfek1RH0YV{i{qy2f#~j@2pKxSbo?EA?;%B6ceSJB`EJ;IkmYy~f3yvu%Qo zDdW&RvRi;m@o8WiCdn(9OlNw&r5ezfcAvJnwuJfM9>dQHCz1MZT_mgNtr4_0Pf*|M3mstx3-0x<+X z+kLmzFo})NyXx7xrLlT>?A&hBxhZGtXiRi2YBV4wKdFZ`*6i4T(>r0VHhI}T4KBOW z9%J=@j^jbL8mE7(HKC)3omS6mvB8Lr+N0gN83`^NOy_HQpc}S7HQ7d;&m5Ue6br|6 zlo~YIx7+VL4(hnG9`qd%o`N}g9MtLl%8R3|u0b8`^$&Ye#~kurj_MfU9|{WaIIN>a zU{^pBw=%3_e9PXB4+)jn1dsrFzk4)-ej&l7C>5Rc2mpO`NLQvGrLqVk)4a3+N??P! zzO|;>5+ZRw=5>^Q>VmhWr25s4Rdr7Wc9g=})qP8G?r&jsr#iSke%8Xhx<_`L09iU2 zLcfsPgjd(lj>AjOf9PNHbx-Z6=AJ5Ryitev?r>=im$p)Z-dxc6 z#TA{tnO=!xG@`Y(E;pqc^TXj2TWI~g_(8nfU8dcC>mS9@D{;i@&eT@vG07?)Nu^9( z`n+6@_~Mb%cAYCNf=@|ON%cW4HEqq3Bwtm=dPC)9!lfRW7zhJz@e}Nr*48G+3(&smYrn}tV!V*MrJS_^jXR{j(wA#xul1rJF&Igt* z^9(-}7U$;+GL%&2c;025P|;#}X&!UZDn_m%Ft z-v*0hwhO5=eM)+W;!^wCmM)}$Tyd3A9NWoVVEq~*N%(&%o^v< zW^LIBJ};a(3z@A^#(cve9UNTzdT>DL%OTB9Cs)&p^ZD$0GC7^i2GQguQcbs#6AzcU zS}E<^0@UB*Mwz{Cj+&U&3faDpd4XJal(q++olJkbzC4{zF5bPnI3K{7hW(T&X-ZcB zDz4=rhj!2ya5^KPA(_fM5<&!Rn#iKKsJOHSlx|I3h0NAN($*R~NFI`i_BIWh>}}8n z=e6<-wNkMZwvuc8_<7% zCc|WEPvc`M^Zj`NxadK#|%`m+RL@>(1f16;W(y1qvp@Ms1=)5PtxaX+bQjTj|b;WBQ>FH;_xC) zStS=~n0Uk^XNJ^Yg`VCD3zY_)xXpi^^@F$ujGbKQJ^4;6d5@0q2wBKD*LY}SPnAK_ z$xx$QpF9R~)m)<$qw$5gDc_U=jMy)$QAnsua5u!vMKWU+V*n_1vsVc2@}l6=(W>eK z@s-U)708WE#BC`4Qk+|tfb^<%{**Q05u|${N&}Fgzg+5Nj?QiOSz@B&v77|~utaMs z?U0;Z?+bCj)H~50-RwUC} z@cKDT1+8b-spC!yLewJdfD>IFh@F^2QRU^ru$wQsAubGp=*8XR@YaO$hxlqc zVUN2s@9U-Ew%bS#Ul?$Ia@NAcxXaysfLjUq2VvuEu``}UJ|Ys09_=6;rv;t?7^NXJ zI3!oAG##LKQ?~8tyA{Hz9Mq(<^O3Yn{dbN`iAk1yVG#+NvK+GF!`ni55ep}OR!2h? z4}OTm|;?h0FR4pMn#vV4)_bE?;voLQY9GS&ScS<5HhVjjiRzMjQ`=WviA zO`Y<~)|mRwd)4YAjha%u!rR9fBXb9nCT&wRhyl#wE1etDAAg3(<8$Lfk2AF~X&h;? uop0*3cZDqex_a=I2mIon_>zQc+k4{|;a*;c8#0q#BJ{8R@I9*)U=43$KN^go%`7|6^CuE#HDJKmPX}bawDd?HEp(yv+c`vyU=ZCiY^gH@5Rac zb8&q1`aB84sm!kBr4lmB+P*Pma~XzZJ#DoSaTt8*+D1gG$=V!mQhJQSps07a!a%I;>#?5dw6SzD(c%FML7l<$<$W!9x01&J?}S}4r~26!#YO81N+*QFLh*tssv zKY=X<=+5Y@ZDt~J|3u*^49(3{i6fPjwX6hQ^qCR2Vemm#y%O|QHs-~1AwJX1`_YWf zqt9V*sv*;rh-(kT-tGXH4(9;fh2czUN`ODb;FIK(T>Vb!?n+jmF2sR|w;X{{+?3Vm zA^f7Ly}(8|kxN#UGIjd(b@-~%N8s>Lnu;?cCzU!Y|58FL)9a=a=1Pf<4%$L2;3iur zlfDo|t7~Zz$XQWxYOhr%=B2r^ajU_Gl-rIKcdF~q(R@;1tkkHnB8Na3}S5>F1q4u`m|lb6$}YH|+fdN2`m z7V%-*Aa()w@9oA9!h7d}>I-G?&f{VAa5((YzcO zN11Gz)}ZQTE*hwCWs7?Mp^L^Ma;+;u9#Dw|9f~}=q6_)5lfLF4WwKM^*}g!LaG?Pi zl9#K@!LnN#j)`4{jUQCsP}Z_eJI+%M02!|~CYbd8PF z&}gxJmW#;M;hd7y?H$QSUO#RTv&GO7kFoHu^pA5Sj*G)QdDRza!1z;E`75;UE*_1= z+!onJ=Q<)@UE3S6wSMo$UI|?Co1C9vv1%^ksOhVUv(7SMzZa!O8;2R#c2pQR31SsL zy?qMSRCZK>7RW`o1{xD6xD%>EP4jDuL={UM(L4NL*TOYZt%`C%n-%yVUePDJLw$<& zv62m!JGvH3%Gd6T_&z%FZY-b*I%%IZDV_}lr6TiV=*KpRC z3{YHi#vPntQ{K;yuO_`meDf&c)TK7*=Maw|in8X+=j}XsOFR1Q5pet5RJj8DZ9Zv# z)Ns420d12V%gCmt_D~iBX3H-6_BNaC-FZ8Gt7fVqGG&vz?y#9^UU87Id~kx4NA0?} zmP-lFR6sB^yS`RA?M0laI6J#8r~JH9CpbP*Rav{Lpb`6oZ*ZrG1mAM4ZXBD7rjv!T za}OJC%;iA0KbPqYNy!y6y|i?P)&`+i{};z zbMCJaZ1l@K=RJa!8H;r3!1}361i^G>y@yd2&n$?ldphH{%OO*e*-i& BKuiDt literal 0 HcmV?d00001 diff --git a/api/accounting/grpc/types_frostfs_fuzz.go b/api/accounting/grpc/types_frostfs_fuzz.go new file mode 100644 index 0000000..5eb5e97 --- /dev/null +++ b/api/accounting/grpc/types_frostfs_fuzz.go @@ -0,0 +1,26 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package accounting + +func DoFuzzProtoDecimal(data []byte) int { + msg := new(Decimal) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONDecimal(data []byte) int { + msg := new(Decimal) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} diff --git a/api/accounting/grpc/types_frostfs_test.go b/api/accounting/grpc/types_frostfs_test.go new file mode 100644 index 0000000..404b75e --- /dev/null +++ b/api/accounting/grpc/types_frostfs_test.go @@ -0,0 +1,21 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package accounting + +import ( + testing "testing" +) + +func FuzzProtoDecimal(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoDecimal(data) + }) +} +func FuzzJSONDecimal(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONDecimal(data) + }) +} diff --git a/api/accounting/json.go b/api/accounting/json.go new file mode 100644 index 0000000..c5ff977 --- /dev/null +++ b/api/accounting/json.go @@ -0,0 +1,14 @@ +package accounting + +import ( + accounting "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/accounting/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" +) + +func (d *Decimal) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(d) +} + +func (d *Decimal) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(d, data, new(accounting.Decimal)) +} diff --git a/api/accounting/marshal.go b/api/accounting/marshal.go new file mode 100644 index 0000000..84771cc --- /dev/null +++ b/api/accounting/marshal.go @@ -0,0 +1,104 @@ +package accounting + +import ( + accounting "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/accounting/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + protoutil "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/util/proto" +) + +const ( + decimalValueField = 1 + decimalPrecisionField = 2 + + balanceReqBodyOwnerField = 1 + + balanceRespBodyDecimalField = 1 +) + +func (d *Decimal) StableMarshal(buf []byte) []byte { + if d == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, d.StableSize()) + } + + var offset int + + offset += protoutil.Int64Marshal(decimalValueField, buf[offset:], d.val) + protoutil.UInt32Marshal(decimalPrecisionField, buf[offset:], d.prec) + + return buf +} + +func (d *Decimal) StableSize() (size int) { + if d == nil { + return 0 + } + + size += protoutil.Int64Size(decimalValueField, d.val) + size += protoutil.UInt32Size(decimalPrecisionField, d.prec) + + return size +} + +func (d *Decimal) Unmarshal(data []byte) error { + return message.Unmarshal(d, data, new(accounting.Decimal)) +} + +func (b *BalanceRequestBody) StableMarshal(buf []byte) []byte { + if b == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, b.StableSize()) + } + + protoutil.NestedStructureMarshal(balanceReqBodyOwnerField, buf, b.ownerID) + + return buf +} + +func (b *BalanceRequestBody) StableSize() (size int) { + if b == nil { + return 0 + } + + size = protoutil.NestedStructureSize(balanceReqBodyOwnerField, b.ownerID) + + return size +} + +func (b *BalanceRequestBody) Unmarshal(data []byte) error { + return message.Unmarshal(b, data, new(accounting.BalanceRequest_Body)) +} + +func (br *BalanceResponseBody) StableMarshal(buf []byte) []byte { + if br == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, br.StableSize()) + } + + protoutil.NestedStructureMarshal(balanceRespBodyDecimalField, buf, br.bal) + + return buf +} + +func (br *BalanceResponseBody) StableSize() (size int) { + if br == nil { + return 0 + } + + size = protoutil.NestedStructureSize(balanceRespBodyDecimalField, br.bal) + + return size +} + +func (br *BalanceResponseBody) Unmarshal(data []byte) error { + return message.Unmarshal(br, data, new(accounting.BalanceResponse_Body)) +} diff --git a/api/accounting/message_test.go b/api/accounting/message_test.go new file mode 100644 index 0000000..214c171 --- /dev/null +++ b/api/accounting/message_test.go @@ -0,0 +1,19 @@ +package accounting_test + +import ( + "testing" + + accountingtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/accounting/test" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + messagetest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message/test" +) + +func TestMessage(t *testing.T) { + messagetest.TestRPCMessage(t, + func(empty bool) message.Message { return accountingtest.GenerateDecimal(empty) }, + func(empty bool) message.Message { return accountingtest.GenerateBalanceRequestBody(empty) }, + func(empty bool) message.Message { return accountingtest.GenerateBalanceRequest(empty) }, + func(empty bool) message.Message { return accountingtest.GenerateBalanceResponseBody(empty) }, + func(empty bool) message.Message { return accountingtest.GenerateBalanceResponse(empty) }, + ) +} diff --git a/api/accounting/test/generate.go b/api/accounting/test/generate.go new file mode 100644 index 0000000..e9f45df --- /dev/null +++ b/api/accounting/test/generate.go @@ -0,0 +1,64 @@ +package accountingtest + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/accounting" + accountingtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs/test" + sessiontest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session/test" +) + +func GenerateBalanceRequest(empty bool) *accounting.BalanceRequest { + m := new(accounting.BalanceRequest) + + if !empty { + m.SetBody(GenerateBalanceRequestBody(false)) + } + + m.SetMetaHeader(sessiontest.GenerateRequestMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateRequestVerificationHeader(empty)) + + return m +} + +func GenerateBalanceRequestBody(empty bool) *accounting.BalanceRequestBody { + m := new(accounting.BalanceRequestBody) + + if !empty { + m.SetOwnerID(accountingtest.GenerateOwnerID(false)) + } + + return m +} + +func GenerateBalanceResponse(empty bool) *accounting.BalanceResponse { + m := new(accounting.BalanceResponse) + + if !empty { + m.SetBody(GenerateBalanceResponseBody(false)) + } + + m.SetMetaHeader(sessiontest.GenerateResponseMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateResponseVerificationHeader(empty)) + + return m +} + +func GenerateBalanceResponseBody(empty bool) *accounting.BalanceResponseBody { + m := new(accounting.BalanceResponseBody) + + if !empty { + m.SetBalance(GenerateDecimal(false)) + } + + return m +} + +func GenerateDecimal(empty bool) *accounting.Decimal { + m := new(accounting.Decimal) + + if !empty { + m.SetValue(1) + m.SetPrecision(2) + } + + return m +} diff --git a/api/acl/bench_test.go b/api/acl/bench_test.go new file mode 100644 index 0000000..200270c --- /dev/null +++ b/api/acl/bench_test.go @@ -0,0 +1,51 @@ +package acl_test + +import ( + "testing" + + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" + aclGrpc "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl/grpc" + acltest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl/test" +) + +func BenchmarkTable_ToGRPCMessage(b *testing.B) { + const size = 4 + + tb := new(acl.Table) + rs := make([]acl.Record, size) + for i := range rs { + fs := make([]acl.HeaderFilter, size) + for j := range fs { + fs[j] = *acltest.GenerateFilter(false) + } + ts := make([]acl.Target, size) + for j := range ts { + ts[j] = *acltest.GenerateTarget(false) + } + + rs[i].SetFilters(fs) + rs[i].SetTargets(ts) + } + tb.SetRecords(rs) + + raw := tb.ToGRPCMessage() + + b.Run("to grpc message", func(b *testing.B) { + b.ReportAllocs() + for range b.N { + raw := tb.ToGRPCMessage() + if len(tb.GetRecords()) != len(raw.(*aclGrpc.EACLTable).Records) { + b.FailNow() + } + } + }) + b.Run("from grpc message", func(b *testing.B) { + b.ReportAllocs() + for range b.N { + tb := new(acl.Table) + if tb.FromGRPCMessage(raw) != nil { + b.FailNow() + } + } + }) +} diff --git a/api/acl/convert.go b/api/acl/convert.go new file mode 100644 index 0000000..3f389e3 --- /dev/null +++ b/api/acl/convert.go @@ -0,0 +1,592 @@ +package acl + +import ( + acl "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape" + apeGRPC "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + refsGRPC "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" +) + +// RoleToGRPCField converts unified role enum into grpc enum. +func RoleToGRPCField(t Role) acl.Role { + switch t { + case RoleUser: + return acl.Role_USER + case RoleSystem: + return acl.Role_SYSTEM + case RoleOthers: + return acl.Role_OTHERS + default: + return acl.Role_ROLE_UNSPECIFIED + } +} + +// RoleFromGRPCField converts grpc enum into unified role enum. +func RoleFromGRPCField(t acl.Role) Role { + switch t { + case acl.Role_USER: + return RoleUser + case acl.Role_SYSTEM: + return RoleSystem + case acl.Role_OTHERS: + return RoleOthers + default: + return RoleUnknown + } +} + +// OperationToGRPCField converts unified operation enum into grpc enum. +func OperationToGRPCField(t Operation) acl.Operation { + switch t { + case OperationPut: + return acl.Operation_PUT + case OperationDelete: + return acl.Operation_DELETE + case OperationGet: + return acl.Operation_GET + case OperationHead: + return acl.Operation_HEAD + case OperationSearch: + return acl.Operation_SEARCH + case OperationRange: + return acl.Operation_GETRANGE + case OperationRangeHash: + return acl.Operation_GETRANGEHASH + default: + return acl.Operation_OPERATION_UNSPECIFIED + } +} + +// OperationFromGRPCField converts grpc enum into unified operation enum. +func OperationFromGRPCField(t acl.Operation) Operation { + switch t { + case acl.Operation_PUT: + return OperationPut + case acl.Operation_DELETE: + return OperationDelete + case acl.Operation_GET: + return OperationGet + case acl.Operation_HEAD: + return OperationHead + case acl.Operation_SEARCH: + return OperationSearch + case acl.Operation_GETRANGE: + return OperationRange + case acl.Operation_GETRANGEHASH: + return OperationRangeHash + default: + return OperationUnknown + } +} + +// ActionToGRPCField converts unified action enum into grpc enum. +func ActionToGRPCField(t Action) acl.Action { + switch t { + case ActionDeny: + return acl.Action_DENY + case ActionAllow: + return acl.Action_ALLOW + default: + return acl.Action_ACTION_UNSPECIFIED + } +} + +// ActionFromGRPCField converts grpc enum into unified action enum. +func ActionFromGRPCField(t acl.Action) Action { + switch t { + case acl.Action_DENY: + return ActionDeny + case acl.Action_ALLOW: + return ActionAllow + default: + return ActionUnknown + } +} + +// HeaderTypeToGRPCField converts unified header type enum into grpc enum. +func HeaderTypeToGRPCField(t HeaderType) acl.HeaderType { + switch t { + case HeaderTypeRequest: + return acl.HeaderType_REQUEST + case HeaderTypeObject: + return acl.HeaderType_OBJECT + case HeaderTypeService: + return acl.HeaderType_SERVICE + default: + return acl.HeaderType_HEADER_UNSPECIFIED + } +} + +// HeaderTypeFromGRPCField converts grpc enum into unified header type enum. +func HeaderTypeFromGRPCField(t acl.HeaderType) HeaderType { + switch t { + case acl.HeaderType_REQUEST: + return HeaderTypeRequest + case acl.HeaderType_OBJECT: + return HeaderTypeObject + case acl.HeaderType_SERVICE: + return HeaderTypeService + default: + return HeaderTypeUnknown + } +} + +// MatchTypeToGRPCField converts unified match type enum into grpc enum. +func MatchTypeToGRPCField(t MatchType) acl.MatchType { + switch t { + case MatchTypeStringEqual: + return acl.MatchType_STRING_EQUAL + case MatchTypeStringNotEqual: + return acl.MatchType_STRING_NOT_EQUAL + default: + return acl.MatchType_MATCH_TYPE_UNSPECIFIED + } +} + +// MatchTypeFromGRPCField converts grpc enum into unified match type enum. +func MatchTypeFromGRPCField(t acl.MatchType) MatchType { + switch t { + case acl.MatchType_STRING_EQUAL: + return MatchTypeStringEqual + case acl.MatchType_STRING_NOT_EQUAL: + return MatchTypeStringNotEqual + default: + return MatchTypeUnknown + } +} + +func (f *HeaderFilter) ToGRPCMessage() grpc.Message { + var m *acl.EACLRecord_Filter + + if f != nil { + m = new(acl.EACLRecord_Filter) + + m.SetKey(f.key) + m.SetValue(f.value) + m.SetHeaderType(HeaderTypeToGRPCField(f.hdrType)) + m.SetMatchType(MatchTypeToGRPCField(f.matchType)) + } + + return m +} + +func (f *HeaderFilter) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*acl.EACLRecord_Filter) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + f.key = v.GetKey() + f.value = v.GetValue() + f.hdrType = HeaderTypeFromGRPCField(v.GetHeaderType()) + f.matchType = MatchTypeFromGRPCField(v.GetMatchType()) + + return nil +} + +func HeaderFiltersToGRPC(fs []HeaderFilter) (res []acl.EACLRecord_Filter) { + if fs != nil { + res = make([]acl.EACLRecord_Filter, 0, len(fs)) + + for i := range fs { + res = append(res, *fs[i].ToGRPCMessage().(*acl.EACLRecord_Filter)) + } + } + + return +} + +func HeaderFiltersFromGRPC(fs []acl.EACLRecord_Filter) (res []HeaderFilter, err error) { + if fs != nil { + res = make([]HeaderFilter, len(fs)) + + for i := range fs { + err = res[i].FromGRPCMessage(&fs[i]) + if err != nil { + return + } + } + } + + return +} + +func (t *Target) ToGRPCMessage() grpc.Message { + var m *acl.EACLRecord_Target + + if t != nil { + m = new(acl.EACLRecord_Target) + + m.SetRole(RoleToGRPCField(t.role)) + m.SetKeys(t.keys) + } + + return m +} + +func (t *Target) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*acl.EACLRecord_Target) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + t.role = RoleFromGRPCField(v.GetRole()) + t.keys = v.GetKeys() + + return nil +} + +func TargetsToGRPC(ts []Target) (res []acl.EACLRecord_Target) { + if ts != nil { + res = make([]acl.EACLRecord_Target, 0, len(ts)) + + for i := range ts { + res = append(res, *ts[i].ToGRPCMessage().(*acl.EACLRecord_Target)) + } + } + + return +} + +func TargetsFromGRPC(fs []acl.EACLRecord_Target) (res []Target, err error) { + if fs != nil { + res = make([]Target, len(fs)) + + for i := range fs { + err = res[i].FromGRPCMessage(&fs[i]) + if err != nil { + return + } + } + } + + return +} + +func (r *Record) ToGRPCMessage() grpc.Message { + var m *acl.EACLRecord + + if r != nil { + m = new(acl.EACLRecord) + + m.SetOperation(OperationToGRPCField(r.op)) + m.SetAction(ActionToGRPCField(r.action)) + m.SetFilters(HeaderFiltersToGRPC(r.filters)) + m.SetTargets(TargetsToGRPC(r.targets)) + } + + return m +} + +func (r *Record) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*acl.EACLRecord) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + r.filters, err = HeaderFiltersFromGRPC(v.GetFilters()) + if err != nil { + return err + } + + r.targets, err = TargetsFromGRPC(v.GetTargets()) + if err != nil { + return err + } + + r.op = OperationFromGRPCField(v.GetOperation()) + r.action = ActionFromGRPCField(v.GetAction()) + + return nil +} + +func RecordsToGRPC(ts []Record) (res []acl.EACLRecord) { + if ts != nil { + res = make([]acl.EACLRecord, 0, len(ts)) + + for i := range ts { + res = append(res, *ts[i].ToGRPCMessage().(*acl.EACLRecord)) + } + } + + return +} + +func RecordsFromGRPC(fs []acl.EACLRecord) (res []Record, err error) { + if fs != nil { + res = make([]Record, len(fs)) + + for i := range fs { + err = res[i].FromGRPCMessage(&fs[i]) + if err != nil { + return + } + } + } + + return +} + +func (t *Table) ToGRPCMessage() grpc.Message { + var m *acl.EACLTable + + if t != nil { + m = new(acl.EACLTable) + + m.SetVersion(t.version.ToGRPCMessage().(*refsGRPC.Version)) + m.SetContainerId(t.cid.ToGRPCMessage().(*refsGRPC.ContainerID)) + m.SetRecords(RecordsToGRPC(t.records)) + } + + return m +} + +func (t *Table) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*acl.EACLTable) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + cid := v.GetContainerId() + if cid == nil { + t.cid = nil + } else { + if t.cid == nil { + t.cid = new(refs.ContainerID) + } + + err = t.cid.FromGRPCMessage(cid) + if err != nil { + return err + } + } + + version := v.GetVersion() + if version == nil { + t.version = nil + } else { + if t.version == nil { + t.version = new(refs.Version) + } + + err = t.version.FromGRPCMessage(version) + if err != nil { + return err + } + } + + t.records, err = RecordsFromGRPC(v.GetRecords()) + + return err +} + +func (l *TokenLifetime) ToGRPCMessage() grpc.Message { + var m *acl.BearerToken_Body_TokenLifetime + + if l != nil { + m = new(acl.BearerToken_Body_TokenLifetime) + + m.SetExp(l.exp) + m.SetIat(l.iat) + m.SetNbf(l.nbf) + } + + return m +} + +func (l *TokenLifetime) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*acl.BearerToken_Body_TokenLifetime) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + l.exp = v.GetExp() + l.iat = v.GetIat() + l.nbf = v.GetNbf() + + return nil +} + +func (c *APEOverride) ToGRPCMessage() grpc.Message { + var m *acl.BearerToken_Body_APEOverride + + if c != nil { + m = new(acl.BearerToken_Body_APEOverride) + + m.SetTarget(c.target.ToGRPCMessage().(*apeGRPC.ChainTarget)) + + if len(c.chains) > 0 { + apeChains := make([]apeGRPC.Chain, len(c.chains)) + for i := range c.chains { + apeChains[i] = *c.chains[i].ToGRPCMessage().(*apeGRPC.Chain) + } + m.SetChains(apeChains) + } + } + + return m +} + +func (c *APEOverride) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*acl.BearerToken_Body_APEOverride) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + if targetGRPC := v.GetTarget(); targetGRPC != nil { + if c.target == nil { + c.target = new(ape.ChainTarget) + } + if err := c.target.FromGRPCMessage(v.GetTarget()); err != nil { + return err + } + } + + if apeChains := v.GetChains(); len(apeChains) > 0 { + c.chains = make([]*ape.Chain, len(apeChains)) + for i := range apeChains { + c.chains[i] = new(ape.Chain) + if err := c.chains[i].FromGRPCMessage(&apeChains[i]); err != nil { + return err + } + } + } + + return nil +} + +func (bt *BearerTokenBody) ToGRPCMessage() grpc.Message { + var m *acl.BearerToken_Body + + if bt != nil { + m = new(acl.BearerToken_Body) + + m.SetOwnerId(bt.ownerID.ToGRPCMessage().(*refsGRPC.OwnerID)) + m.SetLifetime(bt.lifetime.ToGRPCMessage().(*acl.BearerToken_Body_TokenLifetime)) + m.SetEaclTable(bt.eacl.ToGRPCMessage().(*acl.EACLTable)) + m.SetAllowImpersonate(bt.impersonate) + m.SetApeOverride(bt.apeOverride.ToGRPCMessage().(*acl.BearerToken_Body_APEOverride)) + } + + return m +} + +func (bt *BearerTokenBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*acl.BearerToken_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + ownerID := v.GetOwnerId() + if ownerID == nil { + bt.ownerID = nil + } else { + if bt.ownerID == nil { + bt.ownerID = new(refs.OwnerID) + } + + err = bt.ownerID.FromGRPCMessage(ownerID) + if err != nil { + return err + } + } + + lifetime := v.GetLifetime() + if lifetime == nil { + bt.lifetime = nil + } else { + if bt.lifetime == nil { + bt.lifetime = new(TokenLifetime) + } + + err = bt.lifetime.FromGRPCMessage(lifetime) + if err != nil { + return err + } + } + + eacl := v.GetEaclTable() + if eacl == nil { + bt.eacl = nil + } else { + if bt.eacl == nil { + bt.eacl = new(Table) + } + + if err = bt.eacl.FromGRPCMessage(eacl); err != nil { + return err + } + } + + if apeOverrideGRPC := v.GetApeOverride(); apeOverrideGRPC != nil { + if bt.apeOverride == nil { + bt.apeOverride = new(APEOverride) + } + err = bt.apeOverride.FromGRPCMessage(apeOverrideGRPC) + if err != nil { + return err + } + } + + bt.impersonate = v.GetAllowImpersonate() + + return err +} + +func (bt *BearerToken) ToGRPCMessage() grpc.Message { + var m *acl.BearerToken + + if bt != nil { + m = new(acl.BearerToken) + + m.SetBody(bt.body.ToGRPCMessage().(*acl.BearerToken_Body)) + m.SetSignature(bt.sig.ToGRPCMessage().(*refsGRPC.Signature)) + } + + return m +} + +func (bt *BearerToken) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*acl.BearerToken) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + bt.body = nil + } else { + if bt.body == nil { + bt.body = new(BearerTokenBody) + } + + err = bt.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + sig := v.GetSignature() + if sig == nil { + bt.sig = nil + } else { + if bt.sig == nil { + bt.sig = new(refs.Signature) + } + + err = bt.sig.FromGRPCMessage(sig) + } + + return err +} diff --git a/api/acl/filters.go b/api/acl/filters.go new file mode 100644 index 0000000..c1d8afe --- /dev/null +++ b/api/acl/filters.go @@ -0,0 +1,33 @@ +package acl + +// ObjectFilterPrefix is a prefix of key to object header value or property. +const ObjectFilterPrefix = "$Object:" + +const ( + // FilterObjectVersion is a filter key to "version" field of the object header. + FilterObjectVersion = ObjectFilterPrefix + "version" + + // FilterObjectID is a filter key to "object_id" field of the object. + FilterObjectID = ObjectFilterPrefix + "objectID" + + // FilterObjectContainerID is a filter key to "container_id" field of the object header. + FilterObjectContainerID = ObjectFilterPrefix + "containerID" + + // FilterObjectOwnerID is a filter key to "owner_id" field of the object header. + FilterObjectOwnerID = ObjectFilterPrefix + "ownerID" + + // FilterObjectCreationEpoch is a filter key to "creation_epoch" field of the object header. + FilterObjectCreationEpoch = ObjectFilterPrefix + "creationEpoch" + + // FilterObjectPayloadLength is a filter key to "payload_length" field of the object header. + FilterObjectPayloadLength = ObjectFilterPrefix + "payloadLength" + + // FilterObjectPayloadHash is a filter key to "payload_hash" field of the object header. + FilterObjectPayloadHash = ObjectFilterPrefix + "payloadHash" + + // FilterObjectType is a filter key to "object_type" field of the object header. + FilterObjectType = ObjectFilterPrefix + "objectType" + + // FilterObjectHomomorphicHash is a filter key to "homomorphic_hash" field of the object header. + FilterObjectHomomorphicHash = ObjectFilterPrefix + "homomorphicHash" +) diff --git a/api/acl/grpc/types_frostfs.pb.go b/api/acl/grpc/types_frostfs.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..eed28d6ea433c0f200446c51188037605e674b8c GIT binary patch literal 48134 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 N8*76YJEKd${vY;*ga!Zr literal 0 HcmV?d00001 diff --git a/api/acl/grpc/types_frostfs_fuzz.go b/api/acl/grpc/types_frostfs_fuzz.go new file mode 100644 index 0000000..5d5b763 --- /dev/null +++ b/api/acl/grpc/types_frostfs_fuzz.go @@ -0,0 +1,64 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package acl + +func DoFuzzProtoEACLRecord(data []byte) int { + msg := new(EACLRecord) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONEACLRecord(data []byte) int { + msg := new(EACLRecord) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoEACLTable(data []byte) int { + msg := new(EACLTable) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONEACLTable(data []byte) int { + msg := new(EACLTable) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoBearerToken(data []byte) int { + msg := new(BearerToken) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONBearerToken(data []byte) int { + msg := new(BearerToken) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} diff --git a/api/acl/grpc/types_frostfs_test.go b/api/acl/grpc/types_frostfs_test.go new file mode 100644 index 0000000..c6d1c43 --- /dev/null +++ b/api/acl/grpc/types_frostfs_test.go @@ -0,0 +1,41 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package acl + +import ( + testing "testing" +) + +func FuzzProtoEACLRecord(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoEACLRecord(data) + }) +} +func FuzzJSONEACLRecord(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONEACLRecord(data) + }) +} +func FuzzProtoEACLTable(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoEACLTable(data) + }) +} +func FuzzJSONEACLTable(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONEACLTable(data) + }) +} +func FuzzProtoBearerToken(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoBearerToken(data) + }) +} +func FuzzJSONBearerToken(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONBearerToken(data) + }) +} diff --git a/api/acl/json.go b/api/acl/json.go new file mode 100644 index 0000000..9192956 --- /dev/null +++ b/api/acl/json.go @@ -0,0 +1,70 @@ +package acl + +import ( + acl "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" +) + +func (f *HeaderFilter) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(f) +} + +func (f *HeaderFilter) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(f, data, new(acl.EACLRecord_Filter)) +} + +func (t *Target) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(t) +} + +func (t *Target) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(t, data, new(acl.EACLRecord_Target)) +} + +func (a *APEOverride) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(a) +} + +func (a *APEOverride) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(a, data, new(acl.BearerToken_Body_APEOverride)) +} + +func (r *Record) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(r) +} + +func (r *Record) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(r, data, new(acl.EACLRecord)) +} + +func (t *Table) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(t) +} + +func (t *Table) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(t, data, new(acl.EACLTable)) +} + +func (l *TokenLifetime) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(l) +} + +func (l *TokenLifetime) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(l, data, new(acl.BearerToken_Body_TokenLifetime)) +} + +func (bt *BearerTokenBody) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(bt) +} + +func (bt *BearerTokenBody) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(bt, data, new(acl.BearerToken_Body)) +} + +func (bt *BearerToken) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(bt) +} + +func (bt *BearerToken) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(bt, data, new(acl.BearerToken)) +} diff --git a/api/acl/marshal.go b/api/acl/marshal.go new file mode 100644 index 0000000..29bfa06 --- /dev/null +++ b/api/acl/marshal.go @@ -0,0 +1,350 @@ +package acl + +import ( + acl "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + protoutil "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/util/proto" +) + +const ( + filterHeaderTypeField = 1 + filterMatchTypeField = 2 + filterNameField = 3 + filterValueField = 4 + + targetTypeField = 1 + targetKeysField = 2 + + recordOperationField = 1 + recordActionField = 2 + recordFiltersField = 3 + recordTargetsField = 4 + + tableVersionField = 1 + tableContainerIDField = 2 + tableRecordsField = 3 + + lifetimeExpirationField = 1 + lifetimeNotValidBeforeField = 2 + lifetimeIssuedAtField = 3 + + tokenAPEChainsTargetField = 1 + tokenAPEChainsChainsField = 2 + + bearerTokenBodyACLField = 1 + bearerTokenBodyOwnerField = 2 + bearerTokenBodyLifetimeField = 3 + bearerTokenBodyImpersonate = 4 + bearerTokenTokenAPEChainsField = 5 + + bearerTokenBodyField = 1 + bearerTokenSignatureField = 2 +) + +// StableMarshal marshals unified acl table structure in a protobuf +// compatible way without field order shuffle. +func (t *Table) StableMarshal(buf []byte) []byte { + if t == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, t.StableSize()) + } + + var offset int + + offset += protoutil.NestedStructureMarshal(tableVersionField, buf[offset:], t.version) + offset += protoutil.NestedStructureMarshal(tableContainerIDField, buf[offset:], t.cid) + + for i := range t.records { + offset += protoutil.NestedStructureMarshal(tableRecordsField, buf[offset:], &t.records[i]) + } + + return buf +} + +// StableSize of acl table structure marshalled by StableMarshal function. +func (t *Table) StableSize() (size int) { + if t == nil { + return 0 + } + + size += protoutil.NestedStructureSize(tableVersionField, t.version) + size += protoutil.NestedStructureSize(tableContainerIDField, t.cid) + + for i := range t.records { + size += protoutil.NestedStructureSize(tableRecordsField, &t.records[i]) + } + + return size +} + +func (t *Table) Unmarshal(data []byte) error { + return message.Unmarshal(t, data, new(acl.EACLTable)) +} + +// StableMarshal marshals unified acl record structure in a protobuf +// compatible way without field order shuffle. +func (r *Record) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var offset int + + offset += protoutil.EnumMarshal(recordOperationField, buf[offset:], int32(r.op)) + offset += protoutil.EnumMarshal(recordActionField, buf[offset:], int32(r.action)) + + for i := range r.filters { + offset += protoutil.NestedStructureMarshal(recordFiltersField, buf[offset:], &r.filters[i]) + } + + for i := range r.targets { + offset += protoutil.NestedStructureMarshal(recordTargetsField, buf[offset:], &r.targets[i]) + } + + return buf +} + +// StableSize of acl record structure marshalled by StableMarshal function. +func (r *Record) StableSize() (size int) { + if r == nil { + return 0 + } + + size += protoutil.EnumSize(recordOperationField, int32(r.op)) + size += protoutil.EnumSize(recordActionField, int32(r.action)) + + for i := range r.filters { + size += protoutil.NestedStructureSize(recordFiltersField, &r.filters[i]) + } + + for i := range r.targets { + size += protoutil.NestedStructureSize(recordTargetsField, &r.targets[i]) + } + + return size +} + +func (r *Record) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(acl.EACLRecord)) +} + +// StableMarshal marshals unified header filter structure in a protobuf +// compatible way without field order shuffle. +func (f *HeaderFilter) StableMarshal(buf []byte) []byte { + if f == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, f.StableSize()) + } + + var offset int + + offset += protoutil.EnumMarshal(filterHeaderTypeField, buf[offset:], int32(f.hdrType)) + offset += protoutil.EnumMarshal(filterMatchTypeField, buf[offset:], int32(f.matchType)) + offset += protoutil.StringMarshal(filterNameField, buf[offset:], f.key) + protoutil.StringMarshal(filterValueField, buf[offset:], f.value) + + return buf +} + +// StableSize of header filter structure marshalled by StableMarshal function. +func (f *HeaderFilter) StableSize() (size int) { + if f == nil { + return 0 + } + + size += protoutil.EnumSize(filterHeaderTypeField, int32(f.hdrType)) + size += protoutil.EnumSize(filterMatchTypeField, int32(f.matchType)) + size += protoutil.StringSize(filterNameField, f.key) + size += protoutil.StringSize(filterValueField, f.value) + + return size +} + +func (f *HeaderFilter) Unmarshal(data []byte) error { + return message.Unmarshal(f, data, new(acl.EACLRecord_Filter)) +} + +// StableMarshal marshals unified role info structure in a protobuf +// compatible way without field order shuffle. +func (t *Target) StableMarshal(buf []byte) []byte { + if t == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, t.StableSize()) + } + + var offset int + + offset += protoutil.EnumMarshal(targetTypeField, buf[offset:], int32(t.role)) + protoutil.RepeatedBytesMarshal(targetKeysField, buf[offset:], t.keys) + + return buf +} + +// StableSize of role info structure marshalled by StableMarshal function. +func (t *Target) StableSize() (size int) { + if t == nil { + return 0 + } + + size += protoutil.EnumSize(targetTypeField, int32(t.role)) + size += protoutil.RepeatedBytesSize(targetKeysField, t.keys) + + return size +} + +func (t *Target) Unmarshal(data []byte) error { + return message.Unmarshal(t, data, new(acl.EACLRecord_Target)) +} + +func (l *TokenLifetime) StableMarshal(buf []byte) []byte { + if l == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, l.StableSize()) + } + + var offset int + + offset += protoutil.UInt64Marshal(lifetimeExpirationField, buf[offset:], l.exp) + offset += protoutil.UInt64Marshal(lifetimeNotValidBeforeField, buf[offset:], l.nbf) + protoutil.UInt64Marshal(lifetimeIssuedAtField, buf[offset:], l.iat) + + return buf +} + +func (l *TokenLifetime) StableSize() (size int) { + if l == nil { + return 0 + } + + size += protoutil.UInt64Size(lifetimeExpirationField, l.exp) + size += protoutil.UInt64Size(lifetimeNotValidBeforeField, l.nbf) + size += protoutil.UInt64Size(lifetimeIssuedAtField, l.iat) + + return size +} + +func (l *TokenLifetime) Unmarshal(data []byte) error { + return message.Unmarshal(l, data, new(acl.BearerToken_Body_TokenLifetime)) +} + +func (c *APEOverride) StableMarshal(buf []byte) []byte { + if c == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, c.StableSize()) + } + + var offset int + + offset += protoutil.NestedStructureMarshal(tokenAPEChainsTargetField, buf[offset:], c.target) + for i := range c.chains { + offset += protoutil.NestedStructureMarshal(tokenAPEChainsChainsField, buf[offset:], c.chains[i]) + } + + return buf +} + +func (c *APEOverride) StableSize() (size int) { + if c == nil { + return 0 + } + + size += protoutil.NestedStructureSize(tokenAPEChainsTargetField, c.target) + for i := range c.chains { + size += protoutil.NestedStructureSize(tokenAPEChainsChainsField, c.chains[i]) + } + + return size +} + +func (c *APEOverride) Unmarshal(data []byte) error { + return message.Unmarshal(c, data, new(acl.BearerToken_Body_APEOverride)) +} + +func (bt *BearerTokenBody) StableMarshal(buf []byte) []byte { + if bt == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, bt.StableSize()) + } + + var offset int + + offset += protoutil.NestedStructureMarshal(bearerTokenBodyACLField, buf[offset:], bt.eacl) + offset += protoutil.NestedStructureMarshal(bearerTokenBodyOwnerField, buf[offset:], bt.ownerID) + offset += protoutil.NestedStructureMarshal(bearerTokenBodyLifetimeField, buf[offset:], bt.lifetime) + offset += protoutil.BoolMarshal(bearerTokenBodyImpersonate, buf[offset:], bt.impersonate) + protoutil.NestedStructureMarshal(bearerTokenTokenAPEChainsField, buf[offset:], bt.apeOverride) + + return buf +} + +func (bt *BearerTokenBody) StableSize() (size int) { + if bt == nil { + return 0 + } + + size += protoutil.NestedStructureSize(bearerTokenBodyACLField, bt.eacl) + size += protoutil.NestedStructureSize(bearerTokenBodyOwnerField, bt.ownerID) + size += protoutil.NestedStructureSize(bearerTokenBodyLifetimeField, bt.lifetime) + size += protoutil.BoolSize(bearerTokenBodyImpersonate, bt.impersonate) + size += protoutil.NestedStructureSize(bearerTokenTokenAPEChainsField, bt.apeOverride) + + return size +} + +func (bt *BearerTokenBody) Unmarshal(data []byte) error { + return message.Unmarshal(bt, data, new(acl.BearerToken_Body)) +} + +func (bt *BearerToken) StableMarshal(buf []byte) []byte { + if bt == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, bt.StableSize()) + } + + var offset int + + offset += protoutil.NestedStructureMarshal(bearerTokenBodyField, buf[offset:], bt.body) + protoutil.NestedStructureMarshal(bearerTokenSignatureField, buf[offset:], bt.sig) + + return buf +} + +func (bt *BearerToken) StableSize() (size int) { + if bt == nil { + return 0 + } + + size += protoutil.NestedStructureSize(bearerTokenBodyField, bt.body) + size += protoutil.NestedStructureSize(bearerTokenSignatureField, bt.sig) + + return size +} + +func (bt *BearerToken) Unmarshal(data []byte) error { + return message.Unmarshal(bt, data, new(acl.BearerToken)) +} diff --git a/api/acl/message_test.go b/api/acl/message_test.go new file mode 100644 index 0000000..0131137 --- /dev/null +++ b/api/acl/message_test.go @@ -0,0 +1,21 @@ +package acl_test + +import ( + "testing" + + acltest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl/test" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + messagetest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message/test" +) + +func TestMessageConvert(t *testing.T) { + messagetest.TestRPCMessage(t, + func(empty bool) message.Message { return acltest.GenerateFilter(empty) }, + func(empty bool) message.Message { return acltest.GenerateTarget(empty) }, + func(empty bool) message.Message { return acltest.GenerateRecord(empty) }, + func(empty bool) message.Message { return acltest.GenerateTable(empty) }, + func(empty bool) message.Message { return acltest.GenerateTokenLifetime(empty) }, + func(empty bool) message.Message { return acltest.GenerateBearerTokenBody(empty) }, + func(empty bool) message.Message { return acltest.GenerateBearerToken(empty) }, + ) +} diff --git a/api/acl/string.go b/api/acl/string.go new file mode 100644 index 0000000..e5a4462 --- /dev/null +++ b/api/acl/string.go @@ -0,0 +1,110 @@ +package acl + +import ( + acl "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl/grpc" +) + +// String returns string representation of Action. +func (x Action) String() string { + return ActionToGRPCField(x).String() +} + +// FromString parses Action from a string representation. +// It is a reverse action to String(). +// +// Returns true if s was parsed successfully. +func (x *Action) FromString(s string) bool { + var g acl.Action + + ok := g.FromString(s) + + if ok { + *x = ActionFromGRPCField(g) + } + + return ok +} + +// String returns string representation of Role. +func (x Role) String() string { + return RoleToGRPCField(x).String() +} + +// FromString parses Role from a string representation. +// It is a reverse action to String(). +// +// Returns true if s was parsed successfully. +func (x *Role) FromString(s string) bool { + var g acl.Role + + ok := g.FromString(s) + + if ok { + *x = RoleFromGRPCField(g) + } + + return ok +} + +// String returns string representation of Operation. +func (x Operation) String() string { + return OperationToGRPCField(x).String() +} + +// FromString parses Operation from a string representation. +// It is a reverse action to String(). +// +// Returns true if s was parsed successfully. +func (x *Operation) FromString(s string) bool { + var g acl.Operation + + ok := g.FromString(s) + + if ok { + *x = OperationFromGRPCField(g) + } + + return ok +} + +// String returns string representation of MatchType. +func (x MatchType) String() string { + return MatchTypeToGRPCField(x).String() +} + +// FromString parses MatchType from a string representation. +// It is a reverse action to String(). +// +// Returns true if s was parsed successfully. +func (x *MatchType) FromString(s string) bool { + var g acl.MatchType + + ok := g.FromString(s) + + if ok { + *x = MatchTypeFromGRPCField(g) + } + + return ok +} + +// String returns string representation of HeaderType. +func (x HeaderType) String() string { + return HeaderTypeToGRPCField(x).String() +} + +// FromString parses HeaderType from a string representation. +// It is a reverse action to String(). +// +// Returns true if s was parsed successfully. +func (x *HeaderType) FromString(s string) bool { + var g acl.HeaderType + + ok := g.FromString(s) + + if ok { + *x = HeaderTypeFromGRPCField(g) + } + + return ok +} diff --git a/api/acl/test/generate.go b/api/acl/test/generate.go new file mode 100644 index 0000000..8b265ad --- /dev/null +++ b/api/acl/test/generate.go @@ -0,0 +1,144 @@ +package acltest + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" + apetest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape/test" + accountingtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs/test" +) + +func GenerateBearerToken(empty bool) *acl.BearerToken { + m := new(acl.BearerToken) + + if !empty { + m.SetBody(GenerateBearerTokenBody(false)) + } + + m.SetSignature(accountingtest.GenerateSignature(empty)) + + return m +} + +func GenerateBearerTokenBody(empty bool) *acl.BearerTokenBody { + m := new(acl.BearerTokenBody) + + if !empty { + m.SetOwnerID(accountingtest.GenerateOwnerID(false)) + m.SetLifetime(GenerateTokenLifetime(false)) + m.SetAPEOverride(GenerateAPEOverride(empty)) + } + + return m +} + +func GenerateAPEOverride(empty bool) *acl.APEOverride { + var m *acl.APEOverride + + if !empty { + m = new(acl.APEOverride) + m.SetTarget(apetest.GenerateChainTarget(empty)) + m.SetChains(apetest.GenerateRawChains(false, 3)) + } + + return m +} + +func GenerateTable(empty bool) *acl.Table { + m := new(acl.Table) + + if !empty { + m.SetRecords(GenerateRecords(false)) + m.SetContainerID(accountingtest.GenerateContainerID(false)) + } + + m.SetVersion(accountingtest.GenerateVersion(empty)) + + return m +} + +func GenerateRecords(empty bool) []acl.Record { + var rs []acl.Record + + if !empty { + rs = append(rs, + *GenerateRecord(false), + *GenerateRecord(false), + ) + } + + return rs +} + +func GenerateRecord(empty bool) *acl.Record { + m := new(acl.Record) + + if !empty { + m.SetAction(acl.ActionAllow) + m.SetOperation(acl.OperationGet) + m.SetFilters(GenerateFilters(false)) + m.SetTargets(GenerateTargets(false)) + } + + return m +} + +func GenerateFilters(empty bool) []acl.HeaderFilter { + var fs []acl.HeaderFilter + + if !empty { + fs = append(fs, + *GenerateFilter(false), + *GenerateFilter(false), + ) + } + + return fs +} + +func GenerateFilter(empty bool) *acl.HeaderFilter { + m := new(acl.HeaderFilter) + + if !empty { + m.SetKey("key") + m.SetValue("val") + m.SetHeaderType(acl.HeaderTypeRequest) + m.SetMatchType(acl.MatchTypeStringEqual) + } + + return m +} + +func GenerateTargets(empty bool) []acl.Target { + var ts []acl.Target + + if !empty { + ts = append(ts, + *GenerateTarget(false), + *GenerateTarget(false), + ) + } + + return ts +} + +func GenerateTarget(empty bool) *acl.Target { + m := new(acl.Target) + + if !empty { + m.SetRole(acl.RoleSystem) + m.SetKeys([][]byte{{1}, {2}}) + } + + return m +} + +func GenerateTokenLifetime(empty bool) *acl.TokenLifetime { + m := new(acl.TokenLifetime) + + if !empty { + m.SetExp(1) + m.SetIat(2) + m.SetExp(3) + } + + return m +} diff --git a/api/acl/types.go b/api/acl/types.go new file mode 100644 index 0000000..e0bae3a --- /dev/null +++ b/api/acl/types.go @@ -0,0 +1,426 @@ +package acl + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" +) + +// HeaderFilter is a unified structure of FilterInfo +// message from proto definition. +type HeaderFilter struct { + hdrType HeaderType + + matchType MatchType + + key, value string +} + +// Target is a unified structure of Target +// message from proto definition. +type Target struct { + role Role + + keys [][]byte +} + +// Record is a unified structure of EACLRecord +// message from proto definition. +type Record struct { + op Operation + + action Action + + filters []HeaderFilter + + targets []Target +} + +// Table is a unified structure of EACLTable +// message from proto definition. +type Table struct { + version *refs.Version + + cid *refs.ContainerID + + records []Record +} + +type TokenLifetime struct { + exp, nbf, iat uint64 +} + +type APEOverride struct { + target *ape.ChainTarget + + chains []*ape.Chain +} + +type BearerTokenBody struct { + eacl *Table + + ownerID *refs.OwnerID + + lifetime *TokenLifetime + + apeOverride *APEOverride + + impersonate bool +} + +type BearerToken struct { + body *BearerTokenBody + + sig *refs.Signature +} + +// Target is a unified enum of MatchType enum from proto definition. +type MatchType uint32 + +// HeaderType is a unified enum of HeaderType enum from proto definition. +type HeaderType uint32 + +// Action is a unified enum of Action enum from proto definition. +type Action uint32 + +// Operation is a unified enum of Operation enum from proto definition. +type Operation uint32 + +// Role is a unified enum of Role enum from proto definition. +type Role uint32 + +const ( + MatchTypeUnknown MatchType = iota + MatchTypeStringEqual + MatchTypeStringNotEqual +) + +const ( + HeaderTypeUnknown HeaderType = iota + HeaderTypeRequest + HeaderTypeObject + HeaderTypeService +) + +const ( + ActionUnknown Action = iota + ActionAllow + ActionDeny +) + +const ( + OperationUnknown Operation = iota + OperationGet + OperationHead + OperationPut + OperationDelete + OperationSearch + OperationRange + OperationRangeHash +) + +const ( + RoleUnknown Role = iota + RoleUser + RoleSystem + RoleOthers +) + +func (f *HeaderFilter) GetHeaderType() HeaderType { + if f != nil { + return f.hdrType + } + + return HeaderTypeUnknown +} + +func (f *HeaderFilter) SetHeaderType(v HeaderType) { + f.hdrType = v +} + +func (f *HeaderFilter) GetMatchType() MatchType { + if f != nil { + return f.matchType + } + + return MatchTypeUnknown +} + +func (f *HeaderFilter) SetMatchType(v MatchType) { + f.matchType = v +} + +func (f *HeaderFilter) GetKey() string { + if f != nil { + return f.key + } + + return "" +} + +func (f *HeaderFilter) SetKey(v string) { + f.key = v +} + +func (f *HeaderFilter) GetValue() string { + if f != nil { + return f.value + } + + return "" +} + +func (f *HeaderFilter) SetValue(v string) { + f.value = v +} + +func (t *Target) GetRole() Role { + if t != nil { + return t.role + } + + return RoleUnknown +} + +func (t *Target) SetRole(v Role) { + t.role = v +} + +func (t *Target) GetKeys() [][]byte { + if t != nil { + return t.keys + } + + return nil +} + +func (t *Target) SetKeys(v [][]byte) { + t.keys = v +} + +func (r *Record) GetOperation() Operation { + if r != nil { + return r.op + } + + return OperationUnknown +} + +func (r *Record) SetOperation(v Operation) { + r.op = v +} + +func (r *Record) GetAction() Action { + if r != nil { + return r.action + } + + return ActionUnknown +} + +func (r *Record) SetAction(v Action) { + r.action = v +} + +func (r *Record) GetFilters() []HeaderFilter { + if r != nil { + return r.filters + } + + return nil +} + +func (r *Record) SetFilters(v []HeaderFilter) { + r.filters = v +} + +func (r *Record) GetTargets() []Target { + if r != nil { + return r.targets + } + + return nil +} + +func (r *Record) SetTargets(v []Target) { + r.targets = v +} + +func (t *Table) GetVersion() *refs.Version { + if t != nil { + return t.version + } + + return nil +} + +func (t *Table) SetVersion(v *refs.Version) { + t.version = v +} + +func (t *Table) GetContainerID() *refs.ContainerID { + if t != nil { + return t.cid + } + + return nil +} + +func (t *Table) SetContainerID(v *refs.ContainerID) { + t.cid = v +} + +func (t *Table) GetRecords() []Record { + if t != nil { + return t.records + } + + return nil +} + +func (t *Table) SetRecords(v []Record) { + t.records = v +} + +func (l *TokenLifetime) GetExp() uint64 { + if l != nil { + return l.exp + } + + return 0 +} + +func (l *TokenLifetime) SetExp(v uint64) { + l.exp = v +} + +func (l *TokenLifetime) GetNbf() uint64 { + if l != nil { + return l.nbf + } + + return 0 +} + +func (l *TokenLifetime) SetNbf(v uint64) { + l.nbf = v +} + +func (l *TokenLifetime) GetIat() uint64 { + if l != nil { + return l.iat + } + + return 0 +} + +func (l *TokenLifetime) SetIat(v uint64) { + l.iat = v +} + +func (bt *BearerTokenBody) GetEACL() *Table { + if bt != nil { + return bt.eacl + } + + return nil +} + +func (bt *BearerTokenBody) SetEACL(v *Table) { + bt.eacl = v +} + +func (t *APEOverride) GetTarget() *ape.ChainTarget { + if t == nil { + return nil + } + + return t.target +} + +func (t *APEOverride) GetChains() []*ape.Chain { + if t == nil { + return nil + } + + return t.chains +} + +func (t *APEOverride) SetTarget(v *ape.ChainTarget) { + t.target = v +} + +func (t *APEOverride) SetChains(v []*ape.Chain) { + t.chains = v +} + +func (bt *BearerTokenBody) GetAPEOverride() *APEOverride { + if bt != nil { + return bt.apeOverride + } + + return nil +} + +func (bt *BearerTokenBody) SetAPEOverride(v *APEOverride) { + bt.apeOverride = v +} + +func (bt *BearerTokenBody) GetOwnerID() *refs.OwnerID { + if bt != nil { + return bt.ownerID + } + + return nil +} + +func (bt *BearerTokenBody) SetOwnerID(v *refs.OwnerID) { + bt.ownerID = v +} + +func (bt *BearerTokenBody) GetLifetime() *TokenLifetime { + if bt != nil { + return bt.lifetime + } + + return nil +} + +func (bt *BearerTokenBody) SetLifetime(v *TokenLifetime) { + bt.lifetime = v +} + +func (bt *BearerTokenBody) GetImpersonate() bool { + if bt != nil { + return bt.impersonate + } + + return false +} + +func (bt *BearerTokenBody) SetImpersonate(v bool) { + bt.impersonate = v +} + +func (bt *BearerToken) GetBody() *BearerTokenBody { + if bt != nil { + return bt.body + } + + return nil +} + +func (bt *BearerToken) SetBody(v *BearerTokenBody) { + bt.body = v +} + +func (bt *BearerToken) GetSignature() *refs.Signature { + if bt != nil { + return bt.sig + } + + return nil +} + +func (bt *BearerToken) SetSignature(v *refs.Signature) { + bt.sig = v +} diff --git a/api/ape/convert.go b/api/ape/convert.go new file mode 100644 index 0000000..7bb0bde --- /dev/null +++ b/api/ape/convert.go @@ -0,0 +1,132 @@ +package ape + +import ( + "fmt" + + ape "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" +) + +func TargetTypeToGRPCField(typ TargetType) ape.TargetType { + switch typ { + case TargetTypeNamespace: + return ape.TargetType_NAMESPACE + case TargetTypeContainer: + return ape.TargetType_CONTAINER + case TargetTypeUser: + return ape.TargetType_USER + case TargetTypeGroup: + return ape.TargetType_GROUP + default: + return ape.TargetType_UNDEFINED + } +} + +func TargetTypeFromGRPCField(typ ape.TargetType) TargetType { + switch typ { + case ape.TargetType_NAMESPACE: + return TargetTypeNamespace + case ape.TargetType_CONTAINER: + return TargetTypeContainer + case ape.TargetType_USER: + return TargetTypeUser + case ape.TargetType_GROUP: + return TargetTypeGroup + default: + return TargetTypeUndefined + } +} + +func TargetTypeToGRPC(typ TargetType) ape.TargetType { + return ape.TargetType(typ) +} + +func TargetTypeFromGRPC(typ ape.TargetType) TargetType { + return TargetType(typ) +} + +func (v2 *ChainTarget) ToGRPCMessage() grpc.Message { + var mgrpc *ape.ChainTarget + + if v2 != nil { + mgrpc = new(ape.ChainTarget) + + mgrpc.SetType(TargetTypeToGRPC(v2.GetTargetType())) + mgrpc.SetName(v2.GetName()) + } + + return mgrpc +} + +func (v2 *ChainTarget) FromGRPCMessage(m grpc.Message) error { + mgrpc, ok := m.(*ape.ChainTarget) + if !ok { + return message.NewUnexpectedMessageType(m, mgrpc) + } + + v2.SetTargetType(TargetTypeFromGRPC(mgrpc.GetType())) + v2.SetName(mgrpc.GetName()) + + return nil +} + +func (v2 *ChainRaw) ToGRPCMessage() grpc.Message { + var mgrpc *ape.Chain_Raw + + if v2 != nil { + mgrpc = new(ape.Chain_Raw) + + mgrpc.SetRaw(v2.GetRaw()) + } + + return mgrpc +} + +func (v2 *ChainRaw) FromGRPCMessage(m grpc.Message) error { + mgrpc, ok := m.(*ape.Chain_Raw) + if !ok { + return message.NewUnexpectedMessageType(m, mgrpc) + } + + v2.SetRaw(mgrpc.GetRaw()) + + return nil +} + +func (v2 *Chain) ToGRPCMessage() grpc.Message { + var mgrpc *ape.Chain + + if v2 != nil { + mgrpc = new(ape.Chain) + + switch chainKind := v2.GetKind().(type) { + default: + panic(fmt.Sprintf("unsupported chain kind: %T", chainKind)) + case *ChainRaw: + mgrpc.SetKind(chainKind.ToGRPCMessage().(*ape.Chain_Raw)) + } + } + + return mgrpc +} + +func (v2 *Chain) FromGRPCMessage(m grpc.Message) error { + mgrpc, ok := m.(*ape.Chain) + if !ok { + return message.NewUnexpectedMessageType(m, mgrpc) + } + + switch chainKind := mgrpc.GetKind().(type) { + default: + return fmt.Errorf("unsupported chain kind: %T", chainKind) + case *ape.Chain_Raw: + chainRaw := new(ChainRaw) + if err := chainRaw.FromGRPCMessage(chainKind); err != nil { + return err + } + v2.SetKind(chainRaw) + } + + return nil +} diff --git a/api/ape/grpc/types_frostfs.pb.go b/api/ape/grpc/types_frostfs.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..0e204bd2cf85303e88582424a111b959196e83cb GIT binary patch literal 8671 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 literal 0 HcmV?d00001 diff --git a/api/ape/grpc/types_frostfs_fuzz.go b/api/ape/grpc/types_frostfs_fuzz.go new file mode 100644 index 0000000..b7bf367 --- /dev/null +++ b/api/ape/grpc/types_frostfs_fuzz.go @@ -0,0 +1,45 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package ape + +func DoFuzzProtoChainTarget(data []byte) int { + msg := new(ChainTarget) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONChainTarget(data []byte) int { + msg := new(ChainTarget) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoChain(data []byte) int { + msg := new(Chain) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONChain(data []byte) int { + msg := new(Chain) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} diff --git a/api/ape/grpc/types_frostfs_test.go b/api/ape/grpc/types_frostfs_test.go new file mode 100644 index 0000000..93d7eea --- /dev/null +++ b/api/ape/grpc/types_frostfs_test.go @@ -0,0 +1,31 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package ape + +import ( + testing "testing" +) + +func FuzzProtoChainTarget(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoChainTarget(data) + }) +} +func FuzzJSONChainTarget(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONChainTarget(data) + }) +} +func FuzzProtoChain(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoChain(data) + }) +} +func FuzzJSONChain(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONChain(data) + }) +} diff --git a/api/ape/json.go b/api/ape/json.go new file mode 100644 index 0000000..ffa3a8b --- /dev/null +++ b/api/ape/json.go @@ -0,0 +1,14 @@ +package ape + +import ( + ape "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" +) + +func (t *ChainTarget) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(t) +} + +func (t *ChainTarget) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(t, data, new(ape.ChainTarget)) +} diff --git a/api/ape/marshal.go b/api/ape/marshal.go new file mode 100644 index 0000000..e8f377b --- /dev/null +++ b/api/ape/marshal.go @@ -0,0 +1,92 @@ +package ape + +import ( + "fmt" + + ape "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/util/proto" +) + +const ( + chainTargetTargetTypeField = 1 + chainTargetNameField = 2 + + chainRawField = 1 +) + +func (t *ChainTarget) StableSize() (size int) { + if t == nil { + return 0 + } + + size += proto.EnumSize(chainTargetTargetTypeField, int32(t.targeType)) + size += proto.StringSize(chainTargetNameField, t.name) + + return size +} + +func (t *ChainTarget) StableMarshal(buf []byte) []byte { + if t == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, t.StableSize()) + } + + var offset int + + offset += proto.EnumMarshal(chainTargetTargetTypeField, buf[offset:], int32(t.targeType)) + proto.StringMarshal(chainTargetNameField, buf[offset:], t.name) + + return buf +} + +func (t *ChainTarget) Unmarshal(data []byte) error { + return message.Unmarshal(t, data, new(ape.ChainTarget)) +} + +func (c *Chain) StableSize() (size int) { + if c == nil { + return 0 + } + + switch v := c.GetKind().(type) { + case *ChainRaw: + if v != nil { + size += proto.BytesSize(chainRawField, v.GetRaw()) + } + default: + panic(fmt.Sprintf("unsupported chain kind: %T", v)) + } + + return size +} + +func (c *Chain) StableMarshal(buf []byte) []byte { + if c == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, c.StableSize()) + } + + var offset int + + switch v := c.GetKind().(type) { + case *ChainRaw: + if v != nil { + proto.BytesMarshal(chainRawField, buf[offset:], v.GetRaw()) + } + default: + panic(fmt.Sprintf("unsupported chain kind: %T", v)) + } + + return buf +} + +func (c *Chain) Unmarshal(data []byte) error { + return message.Unmarshal(c, data, new(ape.Chain)) +} diff --git a/api/ape/message_test.go b/api/ape/message_test.go new file mode 100644 index 0000000..23b929b --- /dev/null +++ b/api/ape/message_test.go @@ -0,0 +1,15 @@ +package ape_test + +import ( + "testing" + + apetest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape/test" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + messagetest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message/test" +) + +func TestMessageConvert(t *testing.T) { + messagetest.TestRPCMessage(t, + func(empty bool) message.Message { return apetest.GenerateChainTarget(empty) }, + ) +} diff --git a/api/ape/string.go b/api/ape/string.go new file mode 100644 index 0000000..1d26c28 --- /dev/null +++ b/api/ape/string.go @@ -0,0 +1,18 @@ +package ape + +import ( + apegrpc "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape/grpc" +) + +func (tt TargetType) String() string { + return TargetTypeToGRPCField(tt).String() +} + +func (tt *TargetType) FromString(s string) bool { + i, ok := apegrpc.TargetType_value[s] + if ok { + *tt = TargetType(i) + } + + return ok +} diff --git a/api/ape/test/generate.go b/api/ape/test/generate.go new file mode 100644 index 0000000..4fd3dc2 --- /dev/null +++ b/api/ape/test/generate.go @@ -0,0 +1,71 @@ +package test + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape" +) + +func GenerateRawChains(empty bool, n int) []*ape.Chain { + if empty { + return []*ape.Chain{} + } + + res := make([]*ape.Chain, n) + for i := range res { + res[i] = GenerateRawChain(empty) + } + return res +} + +func GenerateRawChain(empty bool) *ape.Chain { + chRaw := new(ape.ChainRaw) + + if empty { + chRaw.SetRaw([]byte("{}")) + } else { + chRaw.SetRaw([]byte(`{ + "ID": "", + "Rules": [ + { + "Status": "Allow", + "Actions": { + "Inverted": false, + "Names": [ + "GetObject" + ] + }, + "Resources": { + "Inverted": false, + "Names": [ + "native:object/*" + ] + }, + "Any": false, + "Condition": [ + { + "Op": "StringEquals", + "Object": "Resource", + "Key": "Department", + "Value": "HR" + } + ] + } + ], + "MatchType": "DenyPriority" + }`)) + } + + ch := new(ape.Chain) + ch.SetKind(chRaw) + return ch +} + +func GenerateChainTarget(empty bool) *ape.ChainTarget { + m := new(ape.ChainTarget) + + if !empty { + m.SetTargetType(ape.TargetTypeContainer) + m.SetName("BzQw5HH3feoxFDD5tCT87Y1726qzgLfxEE7wgtoRzB3R") + } + + return m +} diff --git a/api/ape/types.go b/api/ape/types.go new file mode 100644 index 0000000..467a441 --- /dev/null +++ b/api/ape/types.go @@ -0,0 +1,79 @@ +package ape + +type TargetType uint32 + +const ( + TargetTypeUndefined TargetType = iota + TargetTypeNamespace + TargetTypeContainer + TargetTypeUser + TargetTypeGroup +) + +type ChainTarget struct { + targeType TargetType + + name string +} + +func (ct *ChainTarget) SetTargetType(targeType TargetType) { + ct.targeType = targeType +} + +func (ct *ChainTarget) SetName(name string) { + ct.name = name +} + +func (ct *ChainTarget) GetTargetType() TargetType { + if ct != nil { + return ct.targeType + } + + return 0 +} + +func (ct *ChainTarget) GetName() string { + if ct != nil { + return ct.name + } + + return "" +} + +type chainKind interface { + isChainKind() +} + +type Chain struct { + kind chainKind +} + +func (c *Chain) SetKind(kind chainKind) { + c.kind = kind +} + +func (c *Chain) GetKind() chainKind { + if c == nil { + return nil + } + + return c.kind +} + +type ChainRaw struct { + Raw []byte +} + +func (*ChainRaw) isChainKind() {} + +func (c *ChainRaw) SetRaw(raw []byte) { + c.Raw = raw +} + +func (c *ChainRaw) GetRaw() []byte { + if c == nil { + return nil + } + + return c.Raw +} diff --git a/api/apemanager/convert.go b/api/apemanager/convert.go new file mode 100644 index 0000000..5591791 --- /dev/null +++ b/api/apemanager/convert.go @@ -0,0 +1,358 @@ +package apemanager + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape" + apeGRPC "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape/grpc" + apemanager "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/apemanager/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" +) + +func (reqBody *AddChainRequestBody) ToGRPCMessage() grpc.Message { + var reqBodygrpc *apemanager.AddChainRequest_Body + + if reqBody != nil { + reqBodygrpc = new(apemanager.AddChainRequest_Body) + + reqBodygrpc.SetTarget(reqBody.GetTarget().ToGRPCMessage().(*apeGRPC.ChainTarget)) + reqBodygrpc.SetChain(reqBody.GetChain().ToGRPCMessage().(*apeGRPC.Chain)) + } + + return reqBodygrpc +} + +func (reqBody *AddChainRequestBody) FromGRPCMessage(m grpc.Message) error { + reqBodygrpc, ok := m.(*apemanager.AddChainRequest_Body) + if !ok { + return message.NewUnexpectedMessageType(m, reqBodygrpc) + } + + if targetgrpc := reqBodygrpc.GetTarget(); targetgrpc != nil { + reqBody.target = new(ape.ChainTarget) + if err := reqBody.target.FromGRPCMessage(targetgrpc); err != nil { + return err + } + } + + if chaingrpc := reqBodygrpc.GetChain(); chaingrpc != nil { + reqBody.chain = new(ape.Chain) + if err := reqBody.GetChain().FromGRPCMessage(chaingrpc); err != nil { + return err + } + } + + return nil +} + +func (req *AddChainRequest) ToGRPCMessage() grpc.Message { + var reqgrpc *apemanager.AddChainRequest + + if req != nil { + reqgrpc = new(apemanager.AddChainRequest) + + reqgrpc.SetBody(req.GetBody().ToGRPCMessage().(*apemanager.AddChainRequest_Body)) + req.RequestHeaders.ToMessage(reqgrpc) + } + + return reqgrpc +} + +func (req *AddChainRequest) FromGRPCMessage(m grpc.Message) error { + reqgrpc, ok := m.(*apemanager.AddChainRequest) + if !ok { + return message.NewUnexpectedMessageType(m, reqgrpc) + } + + if reqBodygrpc := reqgrpc.GetBody(); reqBodygrpc != nil { + req.body = new(AddChainRequestBody) + if err := req.body.FromGRPCMessage(reqBodygrpc); err != nil { + return err + } + } + + return req.RequestHeaders.FromMessage(reqgrpc) +} + +func (respBody *AddChainResponseBody) ToGRPCMessage() grpc.Message { + var respBodygrpc *apemanager.AddChainResponse_Body + + if respBody != nil { + respBodygrpc = new(apemanager.AddChainResponse_Body) + + respBodygrpc.SetChainId(respBody.GetChainID()) + } + + return respBodygrpc +} + +func (respBody *AddChainResponseBody) FromGRPCMessage(m grpc.Message) error { + respBodygrpc, ok := m.(*apemanager.AddChainResponse_Body) + if !ok { + return message.NewUnexpectedMessageType(m, respBodygrpc) + } + + respBody.SetChainID(respBodygrpc.GetChainId()) + + return nil +} + +func (resp *AddChainResponse) ToGRPCMessage() grpc.Message { + var respgrpc *apemanager.AddChainResponse + + if resp != nil { + respgrpc = new(apemanager.AddChainResponse) + + respgrpc.SetBody(resp.body.ToGRPCMessage().(*apemanager.AddChainResponse_Body)) + resp.ResponseHeaders.ToMessage(respgrpc) + } + + return respgrpc +} + +func (resp *AddChainResponse) FromGRPCMessage(m grpc.Message) error { + respgrpc, ok := m.(*apemanager.AddChainResponse) + if !ok { + return message.NewUnexpectedMessageType(m, respgrpc) + } + + if respBodygrpc := respgrpc.GetBody(); respBodygrpc != nil { + resp.body = new(AddChainResponseBody) + if err := resp.body.FromGRPCMessage(respBodygrpc); err != nil { + return err + } + } + + return resp.ResponseHeaders.FromMessage(respgrpc) +} + +func (reqBody *RemoveChainRequestBody) ToGRPCMessage() grpc.Message { + var reqBodygrpc *apemanager.RemoveChainRequest_Body + + if reqBody != nil { + reqBodygrpc = new(apemanager.RemoveChainRequest_Body) + + reqBodygrpc.SetTarget(reqBody.target.ToGRPCMessage().(*apeGRPC.ChainTarget)) + reqBodygrpc.SetChainId(reqBody.GetChainID()) + } + + return reqBodygrpc +} + +func (reqBody *RemoveChainRequestBody) FromGRPCMessage(m grpc.Message) error { + reqBodygrpc, ok := m.(*apemanager.RemoveChainRequest_Body) + if !ok { + return message.NewUnexpectedMessageType(m, reqBodygrpc) + } + + if targetgrpc := reqBodygrpc.GetTarget(); targetgrpc != nil { + reqBody.target = new(ape.ChainTarget) + if err := reqBody.target.FromGRPCMessage(targetgrpc); err != nil { + return err + } + } + + reqBody.SetChainID(reqBodygrpc.GetChainId()) + + return nil +} + +func (req *RemoveChainRequest) ToGRPCMessage() grpc.Message { + var reqgrpc *apemanager.RemoveChainRequest + + if req != nil { + reqgrpc = new(apemanager.RemoveChainRequest) + + reqgrpc.SetBody(req.body.ToGRPCMessage().(*apemanager.RemoveChainRequest_Body)) + req.RequestHeaders.ToMessage(reqgrpc) + } + + return reqgrpc +} + +func (req *RemoveChainRequest) FromGRPCMessage(m grpc.Message) error { + reqgrpc, ok := m.(*apemanager.RemoveChainRequest) + if !ok { + return message.NewUnexpectedMessageType(m, reqgrpc) + } + + if reqBodygrpc := reqgrpc.GetBody(); reqBodygrpc != nil { + req.body = new(RemoveChainRequestBody) + if err := req.body.FromGRPCMessage(reqBodygrpc); err != nil { + return err + } + } + + return req.RequestHeaders.FromMessage(reqgrpc) +} + +func (respBody *RemoveChainResponseBody) ToGRPCMessage() grpc.Message { + var respBodygrpc *apemanager.RemoveChainResponse_Body + + if respBody != nil { + respBodygrpc = new(apemanager.RemoveChainResponse_Body) + } + + return respBodygrpc +} + +func (respBody *RemoveChainResponseBody) FromGRPCMessage(m grpc.Message) error { + respBodygrpc, ok := m.(*apemanager.RemoveChainResponse_Body) + if !ok { + return message.NewUnexpectedMessageType(m, respBodygrpc) + } + + return nil +} + +func (resp *RemoveChainResponse) ToGRPCMessage() grpc.Message { + var respgrpc *apemanager.RemoveChainResponse + + if resp != nil { + respgrpc = new(apemanager.RemoveChainResponse) + + respgrpc.SetBody(resp.body.ToGRPCMessage().(*apemanager.RemoveChainResponse_Body)) + resp.ResponseHeaders.ToMessage(respgrpc) + } + + return respgrpc +} + +func (resp *RemoveChainResponse) FromGRPCMessage(m grpc.Message) error { + respgrpc, ok := m.(*apemanager.RemoveChainResponse) + if !ok { + return message.NewUnexpectedMessageType(m, respgrpc) + } + + if respBodygrpc := respgrpc.GetBody(); respBodygrpc != nil { + resp.body = new(RemoveChainResponseBody) + if err := resp.body.FromGRPCMessage(respBodygrpc); err != nil { + return err + } + } + + return resp.ResponseHeaders.FromMessage(respgrpc) +} + +func (reqBody *ListChainsRequestBody) ToGRPCMessage() grpc.Message { + var reqBodygrpc *apemanager.ListChainsRequest_Body + + if reqBody != nil { + reqBodygrpc = new(apemanager.ListChainsRequest_Body) + + reqBodygrpc.SetTarget(reqBody.target.ToGRPCMessage().(*apeGRPC.ChainTarget)) + } + + return reqBodygrpc +} + +func (reqBody *ListChainsRequestBody) FromGRPCMessage(m grpc.Message) error { + reqBodygrpc, ok := m.(*apemanager.ListChainsRequest_Body) + if !ok { + return message.NewUnexpectedMessageType(m, reqBodygrpc) + } + + if targetgrpc := reqBodygrpc.GetTarget(); targetgrpc != nil { + reqBody.target = new(ape.ChainTarget) + if err := reqBody.target.FromGRPCMessage(targetgrpc); err != nil { + return err + } + } + + return nil +} + +func (req *ListChainsRequest) ToGRPCMessage() grpc.Message { + var reqgrpc *apemanager.ListChainsRequest + + if req != nil { + reqgrpc = new(apemanager.ListChainsRequest) + + reqgrpc.SetBody(req.body.ToGRPCMessage().(*apemanager.ListChainsRequest_Body)) + req.RequestHeaders.ToMessage(reqgrpc) + } + + return reqgrpc +} + +func (req *ListChainsRequest) FromGRPCMessage(m grpc.Message) error { + reqgrpc, ok := m.(*apemanager.ListChainsRequest) + if !ok { + return message.NewUnexpectedMessageType(m, reqgrpc) + } + + if reqBodygrpc := reqgrpc.GetBody(); reqBodygrpc != nil { + req.body = new(ListChainsRequestBody) + if err := req.body.FromGRPCMessage(reqBodygrpc); err != nil { + return err + } + } + + return req.RequestHeaders.FromMessage(reqgrpc) +} + +func (respBody *ListChainsResponseBody) ToGRPCMessage() grpc.Message { + var respBodygrpc *apemanager.ListChainsResponse_Body + + if respBody != nil { + respBodygrpc = new(apemanager.ListChainsResponse_Body) + + chainsgrpc := make([]apeGRPC.Chain, 0, len(respBody.GetChains())) + for _, chain := range respBody.GetChains() { + chainsgrpc = append(chainsgrpc, *chain.ToGRPCMessage().(*apeGRPC.Chain)) + } + + respBodygrpc.SetChains(chainsgrpc) + } + + return respBodygrpc +} + +func (respBody *ListChainsResponseBody) FromGRPCMessage(m grpc.Message) error { + respBodygrpc, ok := m.(*apemanager.ListChainsResponse_Body) + if !ok { + return message.NewUnexpectedMessageType(m, respBodygrpc) + } + + chains := make([]*ape.Chain, 0, len(respBodygrpc.GetChains())) + + for _, chaingrpc := range respBodygrpc.GetChains() { + chain := new(ape.Chain) + if err := chain.FromGRPCMessage(&chaingrpc); err != nil { + return err + } + chains = append(chains, chain) + } + + respBody.SetChains(chains) + + return nil +} + +func (resp *ListChainsResponse) ToGRPCMessage() grpc.Message { + var respgrpc *apemanager.ListChainsResponse + + if resp != nil { + respgrpc = new(apemanager.ListChainsResponse) + + respgrpc.SetBody(resp.body.ToGRPCMessage().(*apemanager.ListChainsResponse_Body)) + resp.ResponseHeaders.ToMessage(respgrpc) + } + + return respgrpc +} + +func (resp *ListChainsResponse) FromGRPCMessage(m grpc.Message) error { + respgrpc, ok := m.(*apemanager.ListChainsResponse) + if !ok { + return message.NewUnexpectedMessageType(m, respgrpc) + } + + if respBodygrpc := respgrpc.GetBody(); respBodygrpc != nil { + resp.body = new(ListChainsResponseBody) + if err := resp.body.FromGRPCMessage(respBodygrpc); err != nil { + return err + } + } + + return resp.ResponseHeaders.FromMessage(respgrpc) +} diff --git a/api/apemanager/grpc/service_frostfs.pb.go b/api/apemanager/grpc/service_frostfs.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..402c9080836f7f5e229b38fad474246d77584365 GIT binary patch literal 57305 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 literal 0 HcmV?d00001 diff --git a/api/apemanager/grpc/service_frostfs_fuzz.go b/api/apemanager/grpc/service_frostfs_fuzz.go new file mode 100644 index 0000000..08af63e --- /dev/null +++ b/api/apemanager/grpc/service_frostfs_fuzz.go @@ -0,0 +1,121 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package apemanager + +func DoFuzzProtoAddChainRequest(data []byte) int { + msg := new(AddChainRequest) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONAddChainRequest(data []byte) int { + msg := new(AddChainRequest) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoAddChainResponse(data []byte) int { + msg := new(AddChainResponse) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONAddChainResponse(data []byte) int { + msg := new(AddChainResponse) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoRemoveChainRequest(data []byte) int { + msg := new(RemoveChainRequest) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONRemoveChainRequest(data []byte) int { + msg := new(RemoveChainRequest) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoRemoveChainResponse(data []byte) int { + msg := new(RemoveChainResponse) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONRemoveChainResponse(data []byte) int { + msg := new(RemoveChainResponse) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoListChainsRequest(data []byte) int { + msg := new(ListChainsRequest) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONListChainsRequest(data []byte) int { + msg := new(ListChainsRequest) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoListChainsResponse(data []byte) int { + msg := new(ListChainsResponse) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONListChainsResponse(data []byte) int { + msg := new(ListChainsResponse) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} diff --git a/api/apemanager/grpc/service_frostfs_test.go b/api/apemanager/grpc/service_frostfs_test.go new file mode 100644 index 0000000..5c4653c --- /dev/null +++ b/api/apemanager/grpc/service_frostfs_test.go @@ -0,0 +1,71 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package apemanager + +import ( + testing "testing" +) + +func FuzzProtoAddChainRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoAddChainRequest(data) + }) +} +func FuzzJSONAddChainRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONAddChainRequest(data) + }) +} +func FuzzProtoAddChainResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoAddChainResponse(data) + }) +} +func FuzzJSONAddChainResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONAddChainResponse(data) + }) +} +func FuzzProtoRemoveChainRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoRemoveChainRequest(data) + }) +} +func FuzzJSONRemoveChainRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONRemoveChainRequest(data) + }) +} +func FuzzProtoRemoveChainResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoRemoveChainResponse(data) + }) +} +func FuzzJSONRemoveChainResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONRemoveChainResponse(data) + }) +} +func FuzzProtoListChainsRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoListChainsRequest(data) + }) +} +func FuzzJSONListChainsRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONListChainsRequest(data) + }) +} +func FuzzProtoListChainsResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoListChainsResponse(data) + }) +} +func FuzzJSONListChainsResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONListChainsResponse(data) + }) +} diff --git a/api/apemanager/grpc/service_grpc.pb.go b/api/apemanager/grpc/service_grpc.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..eb11f3fde9dc04cfb3eba36f2dc60edc0e6d9d2e GIT binary patch literal 9917 zcmeHN?Qh$-8UGyr6IK$1_#L5j($R z~JRK zEECa8W;~xoQqAn)SdPKGZd&izRX}OO&9WKHEg!ZzE#l^Oo@$1FoW*icq?tH2=>imM zuwo!GW+W52UMj)NoE!WCa3%jKcF-|+Nc*`-?=!(3QZol66h-`aDWrzL?nRoQ+$;qSA&<*r`1_x>*(^%_}G8k^YC% z^Sf3F2q~Xk4KJLEZk%!^XGt=c1MB4dGRrQ6nagC%!83kN*txlp!Z&B@- zo<9Z>uPsil#X_#cPBbsU5gfA<&CjVe7KyGg^Aa@GG2Sd{91XHmUj%}2J>ur>OeNe#Q`i98|m&_)Tqpii&_-DO24 zI3Sgn3PlzS}2Ua$BtgPTN&SoL;0P4BOU-=8Kj{ByWBjZUTk{`_A7Z;b~j)y-w z8eEQV&qm|n^#rkV^8WH}d`={N|MuNUMb#Q8po`dpIG~y~=yFo%uv{7l2#T&Sz)mI? zXXCS2Lv^Oe{U zr81ECY9h`=s>IuDAr;I%1` zTpHFtWx050Z-XH_AWP6{9K~@o%2)D(Ad0$m88p?Tl&X-KmSuWEcEYLYl+q9T6VRp^ z5#a@guQoHa4xZM+w0p6zpWuS<(k#0GXdm%yfIln29gr^)Vz7U!9R6?1vGT%ZF;+19 zNHK(dR)}@L7s;^N{zXMd)%124qW%muB&s@J%i-HzEe1QwGKR)F6AKhdwm3w^GndOO zVPbKQ9C(+nmqpTmnHm-9X7K-kEA%8~Lz`x)d2HwuJk35lzIF=h{^ftJQ`qhjg0kPX z2(O*MRwwpcFRJVSWZnDye|MunVrti#(W79s%mid<8&5YQzOBqDP`_6CV~jD%sYPI% z-{3%^%Bwpppjr$JAbhx`f7IZ}Rr};Lp9SxQON1B@+4&i@X4`oVW36?PbUCz~kL`!Z zcMrZnXz#Nvtkpj!{!-p8+Xq_(yCHWpq%qAD635&;+MuV)4i|RxyKWZjz-lc3ksNkV zGuu{YPfh}l-J#=PHBj=#(@iaZ21~)IpUqWehC7(576YEbhkqDL)uB5%a{i$CR5TQK zY{4HfjM(r3O#G;~qAA+8FW8#TR)hA!V?9_Tx5FSBJM8mxUH74CrGcjss2Wj(!q2+6 zL~$cojNs^!0d=ixta=~PEF&f`s$FK7v*+a%iJNrVaid@Xq3|#f+vjstFQTG<45K)h`Aa4q9>5Wm>J8SnQBN>&PEn?rp!R;h2<5=R(K! z#EPy-9oVz->8We)8ERQK5iuj@ZU>+pH`b+Q5xmEuFz5y>qjx!1 zk3^PGqiPLlI@s-p!o()jSDOmB8gkvfV;wZ$fXzZzyV_0-^ry;^p&UZR-!YI>6AZ0HsGKi_{VxVa)>{)XRLhmkJ-y{rr&zS|!qN)IKW$J^NqDJS#%Jv~^aPz8T}JND6JU zdg^uadrT8$PAyS|N#BnE!y1E%0b7sNc2>8(ICo_JqM6Kb8BTGW$}qbrNl};?`?i67 zH^rX3Rf%+|{GxXesE$LWhGG$C;AIe8@6)SBs09`>!9_nlx5WyV?^NHROe-Ectrg$# z7Q_Zm{*4t^G7&pSuw|t~ub=eU;ht}v93l;u#m+5WU+B{X_3l|}r;TQ)19112i|(_3 z{@b$dzL!KCP^K?IN=kgWK&TEpGFt}hQGwB(C;C-CH;8R}9UZ{?X!XqLm38iQcm=+F hHc{{15P`_N%-jPjGg^lTdBP2c-hT5s literal 0 HcmV?d00001 diff --git a/api/apemanager/marshal.go b/api/apemanager/marshal.go new file mode 100644 index 0000000..ac6fdde --- /dev/null +++ b/api/apemanager/marshal.go @@ -0,0 +1,205 @@ +package apemanager + +import ( + apemanager "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/apemanager/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/util/proto" +) + +const ( + addChainReqBodyTargetField = 1 + addChainReqBodyChainField = 2 + + addChainRespBodyChainIDField = 1 + + removeChainReqBodyTargetField = 1 + removeChainReqBodyChainField = 2 + + /* + Fields for RemoveResponseBody are missed since RemoveResponseBody is empty. + */ + + listChainsReqBodyTargetField = 1 + + listChainsRespBodyChainsField = 1 +) + +func (rb *AddChainRequestBody) StableSize() (size int) { + if rb == nil { + return 0 + } + + size += proto.NestedStructureSize(addChainReqBodyTargetField, rb.target) + size += proto.NestedStructureSize(addChainReqBodyChainField, rb.chain) + + return size +} + +func (rb *AddChainRequestBody) StableMarshal(buf []byte) []byte { + if rb == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, rb.StableSize()) + } + + var offset int + + offset += proto.NestedStructureMarshal(addChainReqBodyTargetField, buf[offset:], rb.target) + proto.NestedStructureMarshal(addChainReqBodyChainField, buf[offset:], rb.chain) + + return buf +} + +func (rb *AddChainRequestBody) Unmarshal(data []byte) error { + return message.Unmarshal(rb, data, new(apemanager.AddChainRequest_Body)) +} + +func (rb *AddChainResponseBody) StableSize() (size int) { + if rb == nil { + return 0 + } + + size += proto.BytesSize(addChainRespBodyChainIDField, rb.chainID) + + return size +} + +func (rb *AddChainResponseBody) StableMarshal(buf []byte) []byte { + if rb == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, rb.StableSize()) + } + + var offset int + + proto.BytesMarshal(addChainRespBodyChainIDField, buf[offset:], rb.chainID) + + return buf +} + +func (rb *AddChainResponseBody) Unmarshal(data []byte) error { + return message.Unmarshal(rb, data, new(apemanager.AddChainResponse_Body)) +} + +func (rb *RemoveChainRequestBody) StableSize() (size int) { + if rb == nil { + return 0 + } + + size += proto.NestedStructureSize(addChainReqBodyTargetField, rb.target) + size += proto.BytesSize(addChainReqBodyChainField, rb.chainID) + + return size +} + +func (rb *RemoveChainRequestBody) StableMarshal(buf []byte) []byte { + if rb == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, rb.StableSize()) + } + + var offset int + + offset += proto.NestedStructureMarshal(removeChainReqBodyTargetField, buf[offset:], rb.target) + proto.BytesMarshal(removeChainReqBodyChainField, buf[offset:], rb.chainID) + + return buf +} + +func (rb *RemoveChainRequestBody) Unmarshal(data []byte) error { + return message.Unmarshal(rb, data, new(apemanager.RemoveChainRequest_Body)) +} + +func (rb *RemoveChainResponseBody) StableSize() (size int) { + if rb == nil { + return 0 + } + + return size +} + +func (rb *RemoveChainResponseBody) StableMarshal(buf []byte) []byte { + if rb == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, rb.StableSize()) + } + + return buf +} + +func (rb *RemoveChainResponseBody) Unmarshal(data []byte) error { + return message.Unmarshal(rb, data, new(apemanager.RemoveChainResponse_Body)) +} + +func (rb *ListChainsRequestBody) StableSize() (size int) { + if rb == nil { + return 0 + } + + size += proto.NestedStructureSize(listChainsReqBodyTargetField, rb.target) + + return size +} + +func (rb *ListChainsRequestBody) StableMarshal(buf []byte) []byte { + if rb == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, rb.StableSize()) + } + + var offset int + proto.NestedStructureMarshal(addChainReqBodyTargetField, buf[offset:], rb.target) + + return buf +} + +func (rb *ListChainsRequestBody) Unmarshal(data []byte) error { + return message.Unmarshal(rb, data, new(apemanager.ListChainsRequest_Body)) +} + +func (rb *ListChainsResponseBody) StableSize() (size int) { + if rb == nil { + return 0 + } + + for _, chain := range rb.GetChains() { + size += proto.NestedStructureSize(listChainsRespBodyChainsField, chain) + } + + return size +} + +func (rb *ListChainsResponseBody) StableMarshal(buf []byte) []byte { + if rb == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, rb.StableSize()) + } + + var offset int + for _, chain := range rb.GetChains() { + offset += proto.NestedStructureMarshal(listChainsRespBodyChainsField, buf[offset:], chain) + } + + return buf +} + +func (rb *ListChainsResponseBody) Unmarshal(data []byte) error { + return message.Unmarshal(rb, data, new(apemanager.ListChainsResponse_Body)) +} diff --git a/api/apemanager/message_test.go b/api/apemanager/message_test.go new file mode 100644 index 0000000..d64688c --- /dev/null +++ b/api/apemanager/message_test.go @@ -0,0 +1,26 @@ +package apemanager_test + +import ( + "testing" + + apemanagertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/apemanager/test" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + messagetest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message/test" +) + +func TestMessageConvert(t *testing.T) { + messagetest.TestRPCMessage(t, + func(empty bool) message.Message { return apemanagertest.GenerateAddChainRequestBody(empty) }, + func(empty bool) message.Message { return apemanagertest.GenerateAddChainRequest(empty) }, + func(empty bool) message.Message { return apemanagertest.GenerateAddChainResponseBody(empty) }, + func(empty bool) message.Message { return apemanagertest.GenerateAddChainResponse(empty) }, + func(empty bool) message.Message { return apemanagertest.GenerateRemoveChainRequestBody(empty) }, + func(empty bool) message.Message { return apemanagertest.GenerateRemoveChainRequest(empty) }, + func(empty bool) message.Message { return apemanagertest.GenerateRemoveChainResponseBody(empty) }, + func(empty bool) message.Message { return apemanagertest.GenerateRemoveChainResponse(empty) }, + func(empty bool) message.Message { return apemanagertest.GenerateListChainsRequestBody(empty) }, + func(empty bool) message.Message { return apemanagertest.GenerateListChainsRequest(empty) }, + func(empty bool) message.Message { return apemanagertest.GenerateListChainsResponseBody(empty) }, + func(empty bool) message.Message { return apemanagertest.GenerateListChainsResponse(empty) }, + ) +} diff --git a/api/apemanager/status.go b/api/apemanager/status.go new file mode 100644 index 0000000..3b7f435 --- /dev/null +++ b/api/apemanager/status.go @@ -0,0 +1,76 @@ +package apemanager + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status" + statusgrpc "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status/grpc" +) + +// LocalizeFailStatus checks if passed global status.Code is related to ape manager failure and: +// +// then localizes the code and returns true, +// else leaves the code unchanged and returns false. +// +// Arg must be non-nil. +func LocalizeFailStatus(c *status.Code) bool { + return status.LocalizeIfInSection(c, uint32(statusgrpc.Section_SECTION_APE_MANAGER)) +} + +// GlobalizeFail globalizes local code of ape manager failure. +// +// Arg must be non-nil. +func GlobalizeFail(c *status.Code) { + c.GlobalizeSection(uint32(statusgrpc.Section_SECTION_APE_MANAGER)) +} + +const ( + // StatusAPEManagerAccessDenied is a local status.Code value for + // ACCESS_DENIED ape manager failure. + StatusAPEManagerAccessDenied status.Code = iota +) + +const ( + // detailAccessDeniedDesc is a StatusAccessDenied detail ID for + // human-readable description. + detailAccessDeniedDesc = iota +) + +// WriteAccessDeniedDesc writes human-readable description of StatusAccessDenied +// into status.Status as a detail. The status must not be nil. +// +// Existing details are expected to be ID-unique, otherwise undefined behavior. +func WriteAccessDeniedDesc(st *status.Status, desc string) { + var found bool + + st.IterateDetails(func(d *status.Detail) bool { + if d.ID() == detailAccessDeniedDesc { + found = true + d.SetValue([]byte(desc)) + } + + return found + }) + + if !found { + var d status.Detail + + d.SetID(detailAccessDeniedDesc) + d.SetValue([]byte(desc)) + + st.AppendDetails(d) + } +} + +// ReadAccessDeniedDesc looks up for status detail with human-readable description +// of StatusAccessDenied. Returns empty string if detail is missing. +func ReadAccessDeniedDesc(st status.Status) (desc string) { + st.IterateDetails(func(d *status.Detail) bool { + if d.ID() == detailAccessDeniedDesc { + desc = string(d.Value()) + return true + } + + return false + }) + + return +} diff --git a/api/apemanager/status_test.go b/api/apemanager/status_test.go new file mode 100644 index 0000000..af6cd66 --- /dev/null +++ b/api/apemanager/status_test.go @@ -0,0 +1,30 @@ +package apemanager_test + +import ( + "testing" + + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/apemanager" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status" + statustest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status/test" + "github.com/stretchr/testify/require" +) + +func TestStatusCodes(t *testing.T) { + statustest.TestCodes(t, apemanager.LocalizeFailStatus, apemanager.GlobalizeFail, + apemanager.StatusAPEManagerAccessDenied, 5120, + ) +} + +func TestAccessDeniedDesc(t *testing.T) { + var st status.Status + + require.Empty(t, apemanager.ReadAccessDeniedDesc(st)) + + const desc = "some description" + + apemanager.WriteAccessDeniedDesc(&st, desc) + require.Equal(t, desc, apemanager.ReadAccessDeniedDesc(st)) + + apemanager.WriteAccessDeniedDesc(&st, desc+"1") + require.Equal(t, desc+"1", apemanager.ReadAccessDeniedDesc(st)) +} diff --git a/api/apemanager/test/generate.go b/api/apemanager/test/generate.go new file mode 100644 index 0000000..47427d7 --- /dev/null +++ b/api/apemanager/test/generate.go @@ -0,0 +1,143 @@ +package apemanagertest + +import ( + apetest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape/test" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/apemanager" + sessiontest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session/test" +) + +func generateChainID(empty bool) []byte { + if empty { + return []byte{} + } + + return []byte("616c6c6f774f626a476574436e72") +} + +func GenerateAddChainRequestBody(empty bool) *apemanager.AddChainRequestBody { + m := new(apemanager.AddChainRequestBody) + + if !empty { + m.SetTarget(apetest.GenerateChainTarget(empty)) + m.SetChain(apetest.GenerateRawChain(empty)) + } + + return m +} + +func GenerateAddChainRequest(empty bool) *apemanager.AddChainRequest { + m := new(apemanager.AddChainRequest) + + if !empty { + m.SetBody(GenerateAddChainRequestBody(empty)) + m.SetMetaHeader(sessiontest.GenerateRequestMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateRequestVerificationHeader(empty)) + } + + return m +} + +func GenerateAddChainResponseBody(empty bool) *apemanager.AddChainResponseBody { + m := new(apemanager.AddChainResponseBody) + + if !empty { + m.SetChainID(generateChainID(empty)) + } + + return m +} + +func GenerateAddChainResponse(empty bool) *apemanager.AddChainResponse { + m := new(apemanager.AddChainResponse) + + if !empty { + m.SetBody(GenerateAddChainResponseBody(empty)) + m.SetMetaHeader(sessiontest.GenerateResponseMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateResponseVerificationHeader(empty)) + } + + return m +} + +func GenerateRemoveChainRequestBody(empty bool) *apemanager.RemoveChainRequestBody { + m := new(apemanager.RemoveChainRequestBody) + + if !empty { + m.SetChainID(generateChainID(empty)) + m.SetTarget(apetest.GenerateChainTarget(empty)) + } + + return m +} + +func GenerateRemoveChainRequest(empty bool) *apemanager.RemoveChainRequest { + m := new(apemanager.RemoveChainRequest) + + if !empty { + m.SetBody(GenerateRemoveChainRequestBody(empty)) + m.SetMetaHeader(sessiontest.GenerateRequestMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateRequestVerificationHeader(empty)) + } + + return m +} + +func GenerateRemoveChainResponseBody(_ bool) *apemanager.RemoveChainResponseBody { + return new(apemanager.RemoveChainResponseBody) +} + +func GenerateRemoveChainResponse(empty bool) *apemanager.RemoveChainResponse { + m := new(apemanager.RemoveChainResponse) + + if !empty { + m.SetBody(GenerateRemoveChainResponseBody(empty)) + m.SetMetaHeader(sessiontest.GenerateResponseMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateResponseVerificationHeader(empty)) + } + + return m +} + +func GenerateListChainsRequestBody(empty bool) *apemanager.ListChainsRequestBody { + m := new(apemanager.ListChainsRequestBody) + + if !empty { + m.SetTarget(apetest.GenerateChainTarget(empty)) + } + + return m +} + +func GenerateListChainsRequest(empty bool) *apemanager.ListChainsRequest { + m := new(apemanager.ListChainsRequest) + + if !empty { + m.SetBody(GenerateListChainsRequestBody(empty)) + m.SetMetaHeader(sessiontest.GenerateRequestMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateRequestVerificationHeader(empty)) + } + + return m +} + +func GenerateListChainsResponseBody(empty bool) *apemanager.ListChainsResponseBody { + m := new(apemanager.ListChainsResponseBody) + + if !empty { + m.SetChains(apetest.GenerateRawChains(empty, 10)) + } + + return m +} + +func GenerateListChainsResponse(empty bool) *apemanager.ListChainsResponse { + m := new(apemanager.ListChainsResponse) + + if !empty { + m.SetBody(GenerateListChainsResponseBody(empty)) + m.SetMetaHeader(sessiontest.GenerateResponseMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateResponseVerificationHeader(empty)) + } + + return m +} diff --git a/api/apemanager/types.go b/api/apemanager/types.go new file mode 100644 index 0000000..077488b --- /dev/null +++ b/api/apemanager/types.go @@ -0,0 +1,226 @@ +package apemanager + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" +) + +type AddChainRequest struct { + body *AddChainRequestBody + + session.RequestHeaders +} + +func (r *AddChainRequest) SetBody(body *AddChainRequestBody) { + r.body = body +} + +func (r *AddChainRequest) GetBody() *AddChainRequestBody { + if r == nil { + return nil + } + + return r.body +} + +type AddChainRequestBody struct { + target *ape.ChainTarget + + chain *ape.Chain +} + +func (rb *AddChainRequestBody) SetTarget(target *ape.ChainTarget) { + rb.target = target +} + +func (rb *AddChainRequestBody) GetTarget() *ape.ChainTarget { + if rb == nil { + return nil + } + + return rb.target +} + +func (rb *AddChainRequestBody) SetChain(chain *ape.Chain) { + rb.chain = chain +} + +func (rb *AddChainRequestBody) GetChain() *ape.Chain { + if rb == nil { + return nil + } + + return rb.chain +} + +type AddChainResponse struct { + body *AddChainResponseBody + + session.ResponseHeaders +} + +func (r *AddChainResponse) SetBody(body *AddChainResponseBody) { + r.body = body +} + +func (r *AddChainResponse) GetBody() *AddChainResponseBody { + if r == nil { + return nil + } + + return r.body +} + +type AddChainResponseBody struct { + chainID []byte +} + +func (rb *AddChainResponseBody) SetChainID(chainID []byte) { + rb.chainID = chainID +} + +func (rb *AddChainResponseBody) GetChainID() []byte { + if rb == nil { + return nil + } + + return rb.chainID +} + +type RemoveChainRequest struct { + body *RemoveChainRequestBody + + session.RequestHeaders +} + +func (r *RemoveChainRequest) SetBody(body *RemoveChainRequestBody) { + r.body = body +} + +func (r *RemoveChainRequest) GetBody() *RemoveChainRequestBody { + if r == nil { + return nil + } + + return r.body +} + +type RemoveChainRequestBody struct { + target *ape.ChainTarget + + chainID []byte +} + +func (rb *RemoveChainRequestBody) SetTarget(target *ape.ChainTarget) { + rb.target = target +} + +func (rb *RemoveChainRequestBody) GetTarget() *ape.ChainTarget { + if rb == nil { + return nil + } + + return rb.target +} + +func (rb *RemoveChainRequestBody) SetChainID(chainID []byte) { + rb.chainID = chainID +} + +func (rb *RemoveChainRequestBody) GetChainID() []byte { + if rb == nil { + return nil + } + + return rb.chainID +} + +type RemoveChainResponse struct { + body *RemoveChainResponseBody + + session.ResponseHeaders +} + +type RemoveChainResponseBody struct{} + +func (r *RemoveChainResponse) SetBody(body *RemoveChainResponseBody) { + r.body = body +} + +func (r *RemoveChainResponse) GetBody() *RemoveChainResponseBody { + if r == nil { + return nil + } + + return r.body +} + +type ListChainsRequest struct { + body *ListChainsRequestBody + + session.RequestHeaders +} + +func (r *ListChainsRequest) SetBody(body *ListChainsRequestBody) { + r.body = body +} + +func (r *ListChainsRequest) GetBody() *ListChainsRequestBody { + if r == nil { + return nil + } + + return r.body +} + +type ListChainsRequestBody struct { + target *ape.ChainTarget +} + +func (rb *ListChainsRequestBody) SetTarget(target *ape.ChainTarget) { + rb.target = target +} + +func (rb *ListChainsRequestBody) GetTarget() *ape.ChainTarget { + if rb == nil { + return nil + } + + return rb.target +} + +type ListChainsResponse struct { + body *ListChainsResponseBody + + session.ResponseHeaders +} + +func (r *ListChainsResponse) SetBody(body *ListChainsResponseBody) { + r.body = body +} + +func (r *ListChainsResponse) GetBody() *ListChainsResponseBody { + if r == nil { + return nil + } + + return r.body +} + +type ListChainsResponseBody struct { + chains []*ape.Chain + + session.RequestHeaders +} + +func (r *ListChainsResponseBody) SetChains(chains []*ape.Chain) { + r.chains = chains +} + +func (r *ListChainsResponseBody) GetChains() []*ape.Chain { + if r == nil { + return nil + } + + return r.chains +} diff --git a/api/container/attributes.go b/api/container/attributes.go new file mode 100644 index 0000000..288d048 --- /dev/null +++ b/api/container/attributes.go @@ -0,0 +1,90 @@ +package container + +// SysAttributePrefix is a prefix of key to system attribute. +const SysAttributePrefix = "__SYSTEM__" + +const ( + // SysAttributeName is a string of human-friendly container name registered as the domain in NNS contract. + SysAttributeName = SysAttributePrefix + "NAME" + + // SysAttributeZone is a string of zone for container name. + SysAttributeZone = SysAttributePrefix + "ZONE" + + // SysAttributeHomomorphicHashing is a container's homomorphic hashing state. + SysAttributeHomomorphicHashing = SysAttributePrefix + "DISABLE_HOMOMORPHIC_HASHING" +) + +// SysAttributePrefixNeoFS is a prefix of key to system attribute. +// Deprecated: use SysAttributePrefix. +const SysAttributePrefixNeoFS = "__NEOFS__" + +const ( + // SysAttributeNameNeoFS is a string of human-friendly container name registered as the domain in NNS contract. + // Deprecated: use SysAttributeName. + SysAttributeNameNeoFS = SysAttributePrefixNeoFS + "NAME" + + // SysAttributeZoneNeoFS is a string of zone for container name. + // Deprecated: use SysAttributeZone. + SysAttributeZoneNeoFS = SysAttributePrefixNeoFS + "ZONE" + + // SysAttributeHomomorphicHashingNeoFS is a container's homomorphic hashing state. + // Deprecated: use SysAttributeHomomorphicHashing. + SysAttributeHomomorphicHashingNeoFS = SysAttributePrefixNeoFS + "DISABLE_HOMOMORPHIC_HASHING" +) + +// SysAttributeZoneDefault is a default value for SysAttributeZone attribute. +const SysAttributeZoneDefault = "container" + +const disabledHomomorphicHashingValue = "true" + +// HomomorphicHashingState returns container's homomorphic +// hashing state: +// - true if hashing is enabled; +// - false if hashing is disabled. +// +// All container's attributes must be unique, otherwise behavior +// is undefined. +// +// See also SetHomomorphicHashingState. +func (c Container) HomomorphicHashingState() bool { + for i := range c.attr { + if c.attr[i].GetKey() == SysAttributeHomomorphicHashing || c.attr[i].GetKey() == SysAttributeHomomorphicHashingNeoFS { + return c.attr[i].GetValue() != disabledHomomorphicHashingValue + } + } + + return true +} + +// SetHomomorphicHashingState sets homomorphic hashing state for +// container. +// +// All container's attributes must be unique, otherwise behavior +// is undefined. +// +// See also HomomorphicHashingState. +func (c *Container) SetHomomorphicHashingState(enable bool) { + for i := range c.attr { + if c.attr[i].GetKey() == SysAttributeHomomorphicHashing || c.attr[i].GetKey() == SysAttributeHomomorphicHashingNeoFS { + if enable { + // approach without allocation/waste + // coping works since the attributes + // order is not important + c.attr[i] = c.attr[len(c.attr)-1] + c.attr = c.attr[:len(c.attr)-1] + } else { + c.attr[i].SetValue(disabledHomomorphicHashingValue) + } + + return + } + } + + if !enable { + attr := Attribute{} + attr.SetKey(SysAttributeHomomorphicHashing) + attr.SetValue(disabledHomomorphicHashingValue) + + c.attr = append(c.attr, attr) + } +} diff --git a/api/container/attributes_test.go b/api/container/attributes_test.go new file mode 100644 index 0000000..2b00d33 --- /dev/null +++ b/api/container/attributes_test.go @@ -0,0 +1,59 @@ +package container_test + +import ( + "testing" + + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container" + containertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container/test" + "github.com/stretchr/testify/require" +) + +func TestContainer_HomomorphicHashingDisabled(t *testing.T) { + cnr := containertest.GenerateContainer(false) + + t.Run("defaults", func(t *testing.T) { + require.True(t, cnr.HomomorphicHashingState()) + }) + + t.Run("disabled", func(t *testing.T) { + attr := container.Attribute{} + attr.SetKey(container.SysAttributeHomomorphicHashing) + attr.SetValue("NOT_true") + + cnr.SetAttributes(append(cnr.GetAttributes(), attr)) + require.True(t, cnr.HomomorphicHashingState()) + + attr.SetValue("true") + + cnr.SetAttributes([]container.Attribute{attr}) + require.False(t, cnr.HomomorphicHashingState()) + }) +} + +func TestContainer_SetHomomorphicHashingState(t *testing.T) { + cnr := containertest.GenerateContainer(false) + attrs := cnr.GetAttributes() + attrLen := len(attrs) + + cnr.SetHomomorphicHashingState(true) + + // enabling hashing should not add any new attributes + require.Equal(t, attrLen, len(cnr.GetAttributes())) + require.True(t, cnr.HomomorphicHashingState()) + + cnr.SetHomomorphicHashingState(false) + + // disabling hashing should add exactly one attribute + require.Equal(t, attrLen+1, len(cnr.GetAttributes())) + require.False(t, cnr.HomomorphicHashingState()) + + cnr.SetHomomorphicHashingState(true) + + // enabling hashing should remove 1 attribute if + // hashing was disabled before + require.Equal(t, attrLen, len(cnr.GetAttributes())) + require.True(t, cnr.HomomorphicHashingState()) + + // hashing operations should not change any other attributes + require.ElementsMatch(t, attrs, cnr.GetAttributes()) +} diff --git a/api/container/convert.go b/api/container/convert.go new file mode 100644 index 0000000..c91bdfd --- /dev/null +++ b/api/container/convert.go @@ -0,0 +1,764 @@ +package container + +import ( + container "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/netmap" + netmapGRPC "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/netmap/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + refsGRPC "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + sessionGRPC "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session/grpc" +) + +func (a *Attribute) ToGRPCMessage() grpc.Message { + var m *container.Container_Attribute + + if a != nil { + m = new(container.Container_Attribute) + + m.SetKey(a.key) + m.SetValue(a.val) + } + + return m +} + +func (a *Attribute) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*container.Container_Attribute) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + a.key = v.GetKey() + a.val = v.GetValue() + + return nil +} + +func AttributesToGRPC(xs []Attribute) (res []container.Container_Attribute) { + if xs != nil { + res = make([]container.Container_Attribute, 0, len(xs)) + + for i := range xs { + res = append(res, *xs[i].ToGRPCMessage().(*container.Container_Attribute)) + } + } + + return +} + +func AttributesFromGRPC(xs []container.Container_Attribute) (res []Attribute, err error) { + if xs != nil { + res = make([]Attribute, len(xs)) + + for i := range xs { + err = res[i].FromGRPCMessage(&xs[i]) + if err != nil { + return + } + } + } + + return +} + +func (c *Container) ToGRPCMessage() grpc.Message { + var m *container.Container + + if c != nil { + m = new(container.Container) + + m.SetVersion(c.version.ToGRPCMessage().(*refsGRPC.Version)) + m.SetOwnerId(c.ownerID.ToGRPCMessage().(*refsGRPC.OwnerID)) + m.SetPlacementPolicy(c.policy.ToGRPCMessage().(*netmapGRPC.PlacementPolicy)) + m.SetAttributes(AttributesToGRPC(c.attr)) + m.SetBasicAcl(c.basicACL) + m.SetNonce(c.nonce) + } + + return m +} + +func (c *Container) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*container.Container) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + version := v.GetVersion() + if version == nil { + c.version = nil + } else { + if c.version == nil { + c.version = new(refs.Version) + } + + err = c.version.FromGRPCMessage(version) + if err != nil { + return err + } + } + + ownerID := v.GetOwnerId() + if ownerID == nil { + c.ownerID = nil + } else { + if c.ownerID == nil { + c.ownerID = new(refs.OwnerID) + } + + err = c.ownerID.FromGRPCMessage(ownerID) + if err != nil { + return err + } + } + + policy := v.GetPlacementPolicy() + if policy == nil { + c.policy = nil + } else { + if c.policy == nil { + c.policy = new(netmap.PlacementPolicy) + } + + err = c.policy.FromGRPCMessage(policy) + if err != nil { + return err + } + } + + c.attr, err = AttributesFromGRPC(v.GetAttributes()) + if err != nil { + return err + } + + c.basicACL = v.GetBasicAcl() + c.nonce = v.GetNonce() + + return nil +} + +func toSignatureRFC6979(s *refs.Signature) *refsGRPC.SignatureRFC6979 { + var res *refsGRPC.SignatureRFC6979 + + if s != nil { + res = new(refsGRPC.SignatureRFC6979) + res.SetKey(s.GetKey()) + res.SetSign(s.GetSign()) + } + + return res +} + +func (r *PutRequestBody) ToGRPCMessage() grpc.Message { + var m *container.PutRequest_Body + + if r != nil { + m = new(container.PutRequest_Body) + + m.SetContainer(r.cnr.ToGRPCMessage().(*container.Container)) + m.SetSignature(toSignatureRFC6979(r.sig)) + } + + return m +} + +func (r *PutRequestBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*container.PutRequest_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + cnr := v.GetContainer() + if cnr == nil { + r.cnr = nil + } else { + if r.cnr == nil { + r.cnr = new(Container) + } + + err = r.cnr.FromGRPCMessage(cnr) + if err != nil { + return err + } + } + + sig := v.GetSignature() + if sig == nil { + r.sig = nil + } else { + if r.sig == nil { + r.sig = new(refs.Signature) + } + + r.sig.SetKey(sig.GetKey()) + r.sig.SetSign(sig.GetSign()) + } + + return err +} + +func (r *PutRequest) ToGRPCMessage() grpc.Message { + var m *container.PutRequest + + if r != nil { + m = new(container.PutRequest) + + m.SetBody(r.body.ToGRPCMessage().(*container.PutRequest_Body)) + r.RequestHeaders.ToMessage(m) + } + + return m +} + +func (r *PutRequest) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*container.PutRequest) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + r.body = nil + } else { + if r.body == nil { + r.body = new(PutRequestBody) + } + + err = r.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + return r.RequestHeaders.FromMessage(v) +} + +func (r *PutResponseBody) ToGRPCMessage() grpc.Message { + var m *container.PutResponse_Body + + if r != nil { + m = new(container.PutResponse_Body) + + m.SetContainerId(r.cid.ToGRPCMessage().(*refsGRPC.ContainerID)) + } + + return m +} + +func (r *PutResponseBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*container.PutResponse_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + cid := v.GetContainerId() + if cid == nil { + r.cid = nil + } else { + if r.cid == nil { + r.cid = new(refs.ContainerID) + } + + err = r.cid.FromGRPCMessage(cid) + } + + return err +} + +func (r *PutResponse) ToGRPCMessage() grpc.Message { + var m *container.PutResponse + + if r != nil { + m = new(container.PutResponse) + + m.SetBody(r.body.ToGRPCMessage().(*container.PutResponse_Body)) + r.ResponseHeaders.ToMessage(m) + } + + return m +} + +func (r *PutResponse) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*container.PutResponse) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + r.body = nil + } else { + if r.body == nil { + r.body = new(PutResponseBody) + } + + err = r.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + return r.ResponseHeaders.FromMessage(v) +} + +func (r *GetRequestBody) ToGRPCMessage() grpc.Message { + var m *container.GetRequest_Body + + if r != nil { + m = new(container.GetRequest_Body) + + m.SetContainerId(r.cid.ToGRPCMessage().(*refsGRPC.ContainerID)) + } + + return m +} + +func (r *GetRequestBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*container.GetRequest_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + cid := v.GetContainerId() + if cid == nil { + r.cid = nil + } else { + if r.cid == nil { + r.cid = new(refs.ContainerID) + } + + err = r.cid.FromGRPCMessage(cid) + } + + return err +} + +func (r *GetRequest) ToGRPCMessage() grpc.Message { + var m *container.GetRequest + + if r != nil { + m = new(container.GetRequest) + + m.SetBody(r.body.ToGRPCMessage().(*container.GetRequest_Body)) + r.RequestHeaders.ToMessage(m) + } + + return m +} + +func (r *GetRequest) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*container.GetRequest) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + r.body = nil + } else { + if r.body == nil { + r.body = new(GetRequestBody) + } + + err = r.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + return r.RequestHeaders.FromMessage(v) +} + +func (r *GetResponseBody) ToGRPCMessage() grpc.Message { + var m *container.GetResponse_Body + + if r != nil { + m = new(container.GetResponse_Body) + + m.SetContainer(r.cnr.ToGRPCMessage().(*container.Container)) + m.SetSessionToken(r.token.ToGRPCMessage().(*sessionGRPC.SessionToken)) + m.SetSignature(toSignatureRFC6979(r.sig)) + } + + return m +} + +func (r *GetResponseBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*container.GetResponse_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + cnr := v.GetContainer() + if cnr == nil { + r.cnr = nil + } else { + if r.cnr == nil { + r.cnr = new(Container) + } + + err = r.cnr.FromGRPCMessage(cnr) + } + + sig := v.GetSignature() + if sig == nil { + r.sig = nil + } else { + if r.sig == nil { + r.sig = new(refs.Signature) + } + + r.sig.SetKey(sig.GetKey()) + r.sig.SetSign(sig.GetSign()) + } + + token := v.GetSessionToken() + if token == nil { + r.token = nil + } else { + if r.token == nil { + r.token = new(session.Token) + } + + err = r.token.FromGRPCMessage(token) + } + + return err +} + +func (r *GetResponse) ToGRPCMessage() grpc.Message { + var m *container.GetResponse + + if r != nil { + m = new(container.GetResponse) + + m.SetBody(r.body.ToGRPCMessage().(*container.GetResponse_Body)) + r.ResponseHeaders.ToMessage(m) + } + + return m +} + +func (r *GetResponse) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*container.GetResponse) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + r.body = nil + } else { + if r.body == nil { + r.body = new(GetResponseBody) + } + + err = r.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + return r.ResponseHeaders.FromMessage(v) +} + +func (r *DeleteRequestBody) ToGRPCMessage() grpc.Message { + var m *container.DeleteRequest_Body + + if r != nil { + m = new(container.DeleteRequest_Body) + + m.SetContainerId(r.cid.ToGRPCMessage().(*refsGRPC.ContainerID)) + m.SetSignature(toSignatureRFC6979(r.sig)) + } + + return m +} + +func (r *DeleteRequestBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*container.DeleteRequest_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + cid := v.GetContainerId() + if cid == nil { + r.cid = nil + } else { + if r.cid == nil { + r.cid = new(refs.ContainerID) + } + + err = r.cid.FromGRPCMessage(cid) + if err != nil { + return err + } + } + + sig := v.GetSignature() + if sig == nil { + r.sig = nil + } else { + if r.sig == nil { + r.sig = new(refs.Signature) + } + + r.sig.SetKey(sig.GetKey()) + r.sig.SetSign(sig.GetSign()) + } + + return err +} + +func (r *DeleteRequest) ToGRPCMessage() grpc.Message { + var m *container.DeleteRequest + + if r != nil { + m = new(container.DeleteRequest) + + m.SetBody(r.body.ToGRPCMessage().(*container.DeleteRequest_Body)) + r.RequestHeaders.ToMessage(m) + } + + return m +} + +func (r *DeleteRequest) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*container.DeleteRequest) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + r.body = nil + } else { + if r.body == nil { + r.body = new(DeleteRequestBody) + } + + err = r.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + return r.RequestHeaders.FromMessage(v) +} + +func (r *DeleteResponseBody) ToGRPCMessage() grpc.Message { + var m *container.DeleteResponse_Body + + if r != nil { + m = new(container.DeleteResponse_Body) + } + + return m +} + +func (r *DeleteResponseBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*container.DeleteResponse_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + return nil +} + +func (r *DeleteResponse) ToGRPCMessage() grpc.Message { + var m *container.DeleteResponse + + if r != nil { + m = new(container.DeleteResponse) + + m.SetBody(r.body.ToGRPCMessage().(*container.DeleteResponse_Body)) + r.ResponseHeaders.ToMessage(m) + } + + return m +} + +func (r *DeleteResponse) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*container.DeleteResponse) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + r.body = nil + } else { + if r.body == nil { + r.body = new(DeleteResponseBody) + } + + err = r.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + return r.ResponseHeaders.FromMessage(v) +} + +func (r *ListRequestBody) ToGRPCMessage() grpc.Message { + var m *container.ListRequest_Body + + if r != nil { + m = new(container.ListRequest_Body) + + m.SetOwnerId(r.ownerID.ToGRPCMessage().(*refsGRPC.OwnerID)) + } + + return m +} + +func (r *ListRequestBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*container.ListRequest_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + ownerID := v.GetOwnerId() + if ownerID == nil { + r.ownerID = nil + } else { + if r.ownerID == nil { + r.ownerID = new(refs.OwnerID) + } + + err = r.ownerID.FromGRPCMessage(ownerID) + } + + return err +} + +func (r *ListRequest) ToGRPCMessage() grpc.Message { + var m *container.ListRequest + + if r != nil { + m = new(container.ListRequest) + + m.SetBody(r.body.ToGRPCMessage().(*container.ListRequest_Body)) + r.RequestHeaders.ToMessage(m) + } + + return m +} + +func (r *ListRequest) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*container.ListRequest) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + r.body = nil + } else { + if r.body == nil { + r.body = new(ListRequestBody) + } + + err = r.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + return r.RequestHeaders.FromMessage(v) +} + +func (r *ListResponseBody) ToGRPCMessage() grpc.Message { + var m *container.ListResponse_Body + + if r != nil { + m = new(container.ListResponse_Body) + + m.SetContainerIds(refs.ContainerIDsToGRPCMessage(r.cidList)) + } + + return m +} + +func (r *ListResponseBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*container.ListResponse_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + r.cidList, err = refs.ContainerIDsFromGRPCMessage(v.GetContainerIds()) + + return err +} + +func (r *ListResponse) ToGRPCMessage() grpc.Message { + var m *container.ListResponse + + if r != nil { + m = new(container.ListResponse) + + m.SetBody(r.body.ToGRPCMessage().(*container.ListResponse_Body)) + r.ResponseHeaders.ToMessage(m) + } + + return m +} + +func (r *ListResponse) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*container.ListResponse) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + r.body = nil + } else { + if r.body == nil { + r.body = new(ListResponseBody) + } + + err = r.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + return r.ResponseHeaders.FromMessage(v) +} diff --git a/api/container/grpc/service_frostfs.pb.go b/api/container/grpc/service_frostfs.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..07438240cec6d58629892f69a6f99c4f93142bbd GIT binary patch literal 76792 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 literal 0 HcmV?d00001 diff --git a/api/container/grpc/service_frostfs_fuzz.go b/api/container/grpc/service_frostfs_fuzz.go new file mode 100644 index 0000000..7e6d6e6 --- /dev/null +++ b/api/container/grpc/service_frostfs_fuzz.go @@ -0,0 +1,159 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package container + +func DoFuzzProtoPutRequest(data []byte) int { + msg := new(PutRequest) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONPutRequest(data []byte) int { + msg := new(PutRequest) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoPutResponse(data []byte) int { + msg := new(PutResponse) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONPutResponse(data []byte) int { + msg := new(PutResponse) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoDeleteRequest(data []byte) int { + msg := new(DeleteRequest) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONDeleteRequest(data []byte) int { + msg := new(DeleteRequest) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoDeleteResponse(data []byte) int { + msg := new(DeleteResponse) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONDeleteResponse(data []byte) int { + msg := new(DeleteResponse) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoGetRequest(data []byte) int { + msg := new(GetRequest) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONGetRequest(data []byte) int { + msg := new(GetRequest) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoGetResponse(data []byte) int { + msg := new(GetResponse) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONGetResponse(data []byte) int { + msg := new(GetResponse) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoListRequest(data []byte) int { + msg := new(ListRequest) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONListRequest(data []byte) int { + msg := new(ListRequest) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoListResponse(data []byte) int { + msg := new(ListResponse) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONListResponse(data []byte) int { + msg := new(ListResponse) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} diff --git a/api/container/grpc/service_frostfs_test.go b/api/container/grpc/service_frostfs_test.go new file mode 100644 index 0000000..804b89c --- /dev/null +++ b/api/container/grpc/service_frostfs_test.go @@ -0,0 +1,91 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package container + +import ( + testing "testing" +) + +func FuzzProtoPutRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoPutRequest(data) + }) +} +func FuzzJSONPutRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONPutRequest(data) + }) +} +func FuzzProtoPutResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoPutResponse(data) + }) +} +func FuzzJSONPutResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONPutResponse(data) + }) +} +func FuzzProtoDeleteRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoDeleteRequest(data) + }) +} +func FuzzJSONDeleteRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONDeleteRequest(data) + }) +} +func FuzzProtoDeleteResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoDeleteResponse(data) + }) +} +func FuzzJSONDeleteResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONDeleteResponse(data) + }) +} +func FuzzProtoGetRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoGetRequest(data) + }) +} +func FuzzJSONGetRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONGetRequest(data) + }) +} +func FuzzProtoGetResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoGetResponse(data) + }) +} +func FuzzJSONGetResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONGetResponse(data) + }) +} +func FuzzProtoListRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoListRequest(data) + }) +} +func FuzzJSONListRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONListRequest(data) + }) +} +func FuzzProtoListResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoListResponse(data) + }) +} +func FuzzJSONListResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONListResponse(data) + }) +} diff --git a/api/container/grpc/service_grpc.pb.go b/api/container/grpc/service_grpc.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..ea226043cebeb4a455708b9ae7f0e130a350a898 GIT binary patch literal 11737 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 TWX2M*(%oeU47LfvFQb0}-gwDh literal 0 HcmV?d00001 diff --git a/api/lock/grpc/types_frostfs_fuzz.go b/api/lock/grpc/types_frostfs_fuzz.go new file mode 100644 index 0000000..cb55151 --- /dev/null +++ b/api/lock/grpc/types_frostfs_fuzz.go @@ -0,0 +1,26 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package lock + +func DoFuzzProtoLock(data []byte) int { + msg := new(Lock) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONLock(data []byte) int { + msg := new(Lock) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} diff --git a/api/lock/grpc/types_frostfs_test.go b/api/lock/grpc/types_frostfs_test.go new file mode 100644 index 0000000..7c69064 --- /dev/null +++ b/api/lock/grpc/types_frostfs_test.go @@ -0,0 +1,21 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package lock + +import ( + testing "testing" +) + +func FuzzProtoLock(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoLock(data) + }) +} +func FuzzJSONLock(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONLock(data) + }) +} diff --git a/api/netmap/convert.go b/api/netmap/convert.go new file mode 100644 index 0000000..f8117a5 --- /dev/null +++ b/api/netmap/convert.go @@ -0,0 +1,916 @@ +package netmap + +import ( + netmap "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/netmap/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + refsGRPC "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" +) + +func (f *Filter) ToGRPCMessage() grpc.Message { + var m *netmap.Filter + + if f != nil { + m = new(netmap.Filter) + + m.SetKey(f.key) + m.SetValue(f.value) + m.SetName(f.name) + m.SetOp(OperationToGRPCMessage(f.op)) + m.SetFilters(FiltersToGRPC(f.filters)) + } + + return m +} + +func (f *Filter) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.Filter) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + f.filters, err = FiltersFromGRPC(v.GetFilters()) + if err != nil { + return err + } + + f.key = v.GetKey() + f.value = v.GetValue() + f.name = v.GetName() + f.op = OperationFromGRPCMessage(v.GetOp()) + + return nil +} + +func FiltersToGRPC(fs []Filter) (res []netmap.Filter) { + if fs != nil { + res = make([]netmap.Filter, 0, len(fs)) + + for i := range fs { + res = append(res, *fs[i].ToGRPCMessage().(*netmap.Filter)) + } + } + + return +} + +func FiltersFromGRPC(fs []netmap.Filter) (res []Filter, err error) { + if fs != nil { + res = make([]Filter, len(fs)) + + for i := range fs { + err = res[i].FromGRPCMessage(&fs[i]) + if err != nil { + return + } + } + } + + return +} + +func (s *Selector) ToGRPCMessage() grpc.Message { + var m *netmap.Selector + + if s != nil { + m = new(netmap.Selector) + + m.SetName(s.name) + m.SetAttribute(s.attribute) + m.SetFilter(s.filter) + m.SetCount(s.count) + m.SetClause(ClauseToGRPCMessage(s.clause)) + } + + return m +} + +func (s *Selector) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.Selector) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + s.name = v.GetName() + s.attribute = v.GetAttribute() + s.filter = v.GetFilter() + s.count = v.GetCount() + s.clause = ClauseFromGRPCMessage(v.GetClause()) + + return nil +} + +func SelectorsToGRPC(ss []Selector) (res []netmap.Selector) { + if ss != nil { + res = make([]netmap.Selector, 0, len(ss)) + + for i := range ss { + res = append(res, *ss[i].ToGRPCMessage().(*netmap.Selector)) + } + } + + return +} + +func SelectorsFromGRPC(ss []netmap.Selector) (res []Selector, err error) { + if ss != nil { + res = make([]Selector, len(ss)) + + for i := range ss { + err = res[i].FromGRPCMessage(&ss[i]) + if err != nil { + return + } + } + } + + return +} + +func (r *Replica) ToGRPCMessage() grpc.Message { + var m *netmap.Replica + + if r != nil { + m = new(netmap.Replica) + + m.SetSelector(r.selector) + m.SetCount(r.count) + m.EcDataCount = r.ecDataCount + m.EcParityCount = r.ecParityCount + } + + return m +} + +func (r *Replica) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.Replica) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + r.selector = v.GetSelector() + r.count = v.GetCount() + r.ecDataCount = v.GetEcDataCount() + r.ecParityCount = v.GetEcParityCount() + + return nil +} + +func ReplicasToGRPC(rs []Replica) (res []netmap.Replica) { + if rs != nil { + res = make([]netmap.Replica, 0, len(rs)) + + for i := range rs { + res = append(res, *rs[i].ToGRPCMessage().(*netmap.Replica)) + } + } + + return +} + +func ReplicasFromGRPC(rs []netmap.Replica) (res []Replica, err error) { + if rs != nil { + res = make([]Replica, len(rs)) + + for i := range rs { + err = res[i].FromGRPCMessage(&rs[i]) + if err != nil { + return + } + } + } + + return +} + +func (p *PlacementPolicy) ToGRPCMessage() grpc.Message { + var m *netmap.PlacementPolicy + + if p != nil { + m = new(netmap.PlacementPolicy) + + m.SetFilters(FiltersToGRPC(p.filters)) + m.SetSelectors(SelectorsToGRPC(p.selectors)) + m.SetReplicas(ReplicasToGRPC(p.replicas)) + m.SetContainerBackupFactor(p.backupFactor) + m.SetUnique(p.unique) + } + + return m +} + +func (p *PlacementPolicy) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.PlacementPolicy) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + p.filters, err = FiltersFromGRPC(v.GetFilters()) + if err != nil { + return err + } + + p.selectors, err = SelectorsFromGRPC(v.GetSelectors()) + if err != nil { + return err + } + + p.replicas, err = ReplicasFromGRPC(v.GetReplicas()) + if err != nil { + return err + } + + p.backupFactor = v.GetContainerBackupFactor() + + p.unique = v.GetUnique() + + return nil +} + +func ClauseToGRPCMessage(n Clause) netmap.Clause { + return netmap.Clause(n) +} + +func ClauseFromGRPCMessage(n netmap.Clause) Clause { + return Clause(n) +} + +func OperationToGRPCMessage(n Operation) netmap.Operation { + return netmap.Operation(n) +} + +func OperationFromGRPCMessage(n netmap.Operation) Operation { + return Operation(n) +} + +func NodeStateToGRPCMessage(n NodeState) netmap.NodeInfo_State { + return netmap.NodeInfo_State(n) +} + +func NodeStateFromRPCMessage(n netmap.NodeInfo_State) NodeState { + return NodeState(n) +} + +func (a *Attribute) ToGRPCMessage() grpc.Message { + var m *netmap.NodeInfo_Attribute + + if a != nil { + m = new(netmap.NodeInfo_Attribute) + + m.SetKey(a.key) + m.SetValue(a.value) + m.SetParents(a.parents) + } + + return m +} + +func (a *Attribute) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.NodeInfo_Attribute) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + a.key = v.GetKey() + a.value = v.GetValue() + a.parents = v.GetParents() + + return nil +} + +func AttributesToGRPC(as []Attribute) (res []netmap.NodeInfo_Attribute) { + if as != nil { + res = make([]netmap.NodeInfo_Attribute, 0, len(as)) + + for i := range as { + res = append(res, *as[i].ToGRPCMessage().(*netmap.NodeInfo_Attribute)) + } + } + + return +} + +func AttributesFromGRPC(as []netmap.NodeInfo_Attribute) (res []Attribute, err error) { + if as != nil { + res = make([]Attribute, len(as)) + + for i := range as { + err = res[i].FromGRPCMessage(&as[i]) + if err != nil { + return + } + } + } + + return +} + +func (ni *NodeInfo) ToGRPCMessage() grpc.Message { + var m *netmap.NodeInfo + + if ni != nil { + m = new(netmap.NodeInfo) + + m.SetPublicKey(ni.publicKey) + m.SetAddresses(ni.addresses) + m.SetState(NodeStateToGRPCMessage(ni.state)) + m.SetAttributes(AttributesToGRPC(ni.attributes)) + } + + return m +} + +func (ni *NodeInfo) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.NodeInfo) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + ni.attributes, err = AttributesFromGRPC(v.GetAttributes()) + if err != nil { + return err + } + + ni.publicKey = v.GetPublicKey() + ni.addresses = v.GetAddresses() + ni.state = NodeStateFromRPCMessage(v.GetState()) + + return nil +} + +func (l *LocalNodeInfoRequestBody) ToGRPCMessage() grpc.Message { + var m *netmap.LocalNodeInfoRequest_Body + + if l != nil { + m = new(netmap.LocalNodeInfoRequest_Body) + } + + return m +} + +func (l *LocalNodeInfoRequestBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.LocalNodeInfoRequest_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + return nil +} + +func (l *LocalNodeInfoRequest) ToGRPCMessage() grpc.Message { + var m *netmap.LocalNodeInfoRequest + + if l != nil { + m = new(netmap.LocalNodeInfoRequest) + + m.SetBody(l.body.ToGRPCMessage().(*netmap.LocalNodeInfoRequest_Body)) + l.RequestHeaders.ToMessage(m) + } + + return m +} + +func (l *LocalNodeInfoRequest) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.LocalNodeInfoRequest) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + l.body = nil + } else { + if l.body == nil { + l.body = new(LocalNodeInfoRequestBody) + } + + err = l.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + return l.RequestHeaders.FromMessage(v) +} + +func (l *LocalNodeInfoResponseBody) ToGRPCMessage() grpc.Message { + var m *netmap.LocalNodeInfoResponse_Body + + if l != nil { + m = new(netmap.LocalNodeInfoResponse_Body) + + m.SetVersion(l.version.ToGRPCMessage().(*refsGRPC.Version)) + m.SetNodeInfo(l.nodeInfo.ToGRPCMessage().(*netmap.NodeInfo)) + } + + return m +} + +func (l *LocalNodeInfoResponseBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.LocalNodeInfoResponse_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + version := v.GetVersion() + if version == nil { + l.version = nil + } else { + if l.version == nil { + l.version = new(refs.Version) + } + + err = l.version.FromGRPCMessage(version) + if err != nil { + return err + } + } + + nodeInfo := v.GetNodeInfo() + if nodeInfo == nil { + l.nodeInfo = nil + } else { + if l.nodeInfo == nil { + l.nodeInfo = new(NodeInfo) + } + + err = l.nodeInfo.FromGRPCMessage(nodeInfo) + } + + return err +} + +func (l *LocalNodeInfoResponse) ToGRPCMessage() grpc.Message { + var m *netmap.LocalNodeInfoResponse + + if l != nil { + m = new(netmap.LocalNodeInfoResponse) + + m.SetBody(l.body.ToGRPCMessage().(*netmap.LocalNodeInfoResponse_Body)) + l.ResponseHeaders.ToMessage(m) + } + + return m +} + +func (l *LocalNodeInfoResponse) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.LocalNodeInfoResponse) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + l.body = nil + } else { + if l.body == nil { + l.body = new(LocalNodeInfoResponseBody) + } + + err = l.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + return l.ResponseHeaders.FromMessage(v) +} + +func (x *NetworkParameter) ToGRPCMessage() grpc.Message { + var m *netmap.NetworkConfig_Parameter + + if x != nil { + m = new(netmap.NetworkConfig_Parameter) + + m.SetKey(x.k) + m.SetValue(x.v) + } + + return m +} + +func (x *NetworkParameter) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.NetworkConfig_Parameter) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + x.k = v.GetKey() + x.v = v.GetValue() + + return nil +} + +func (x *NetworkConfig) ToGRPCMessage() grpc.Message { + var m *netmap.NetworkConfig + + if x != nil { + m = new(netmap.NetworkConfig) + + var ps []netmap.NetworkConfig_Parameter + + if ln := len(x.ps); ln > 0 { + ps = make([]netmap.NetworkConfig_Parameter, 0, ln) + + for i := range ln { + ps = append(ps, *x.ps[i].ToGRPCMessage().(*netmap.NetworkConfig_Parameter)) + } + } + + m.SetParameters(ps) + } + + return m +} + +func (x *NetworkConfig) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.NetworkConfig) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var ( + ps []NetworkParameter + psV2 = v.GetParameters() + ) + + if psV2 != nil { + ln := len(psV2) + + ps = make([]NetworkParameter, ln) + + for i := range ln { + if err := ps[i].FromGRPCMessage(&psV2[i]); err != nil { + return err + } + } + } + + x.ps = ps + + return nil +} + +func (i *NetworkInfo) ToGRPCMessage() grpc.Message { + var m *netmap.NetworkInfo + + if i != nil { + m = new(netmap.NetworkInfo) + + m.SetMagicNumber(i.magicNum) + m.SetCurrentEpoch(i.curEpoch) + m.SetMsPerBlock(i.msPerBlock) + m.SetNetworkConfig(i.netCfg.ToGRPCMessage().(*netmap.NetworkConfig)) + } + + return m +} + +func (i *NetworkInfo) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.NetworkInfo) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + netCfg := v.GetNetworkConfig() + if netCfg == nil { + i.netCfg = nil + } else { + if i.netCfg == nil { + i.netCfg = new(NetworkConfig) + } + + err = i.netCfg.FromGRPCMessage(netCfg) + if err != nil { + return err + } + } + + i.magicNum = v.GetMagicNumber() + i.curEpoch = v.GetCurrentEpoch() + i.msPerBlock = v.GetMsPerBlock() + + return nil +} + +func (l *NetworkInfoRequestBody) ToGRPCMessage() grpc.Message { + var m *netmap.NetworkInfoRequest_Body + + if l != nil { + m = new(netmap.NetworkInfoRequest_Body) + } + + return m +} + +func (l *NetworkInfoRequestBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.NetworkInfoRequest_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + return nil +} + +func (l *NetworkInfoRequest) ToGRPCMessage() grpc.Message { + var m *netmap.NetworkInfoRequest + + if l != nil { + m = new(netmap.NetworkInfoRequest) + + m.SetBody(l.body.ToGRPCMessage().(*netmap.NetworkInfoRequest_Body)) + l.RequestHeaders.ToMessage(m) + } + + return m +} + +func (l *NetworkInfoRequest) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.NetworkInfoRequest) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + l.body = nil + } else { + if l.body == nil { + l.body = new(NetworkInfoRequestBody) + } + + err = l.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + return l.RequestHeaders.FromMessage(v) +} + +func (i *NetworkInfoResponseBody) ToGRPCMessage() grpc.Message { + var m *netmap.NetworkInfoResponse_Body + + if i != nil { + m = new(netmap.NetworkInfoResponse_Body) + + m.SetNetworkInfo(i.netInfo.ToGRPCMessage().(*netmap.NetworkInfo)) + } + + return m +} + +func (i *NetworkInfoResponseBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.NetworkInfoResponse_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + netInfo := v.GetNetworkInfo() + if netInfo == nil { + i.netInfo = nil + } else { + if i.netInfo == nil { + i.netInfo = new(NetworkInfo) + } + + err = i.netInfo.FromGRPCMessage(netInfo) + } + + return err +} + +func (l *NetworkInfoResponse) ToGRPCMessage() grpc.Message { + var m *netmap.NetworkInfoResponse + + if l != nil { + m = new(netmap.NetworkInfoResponse) + + m.SetBody(l.body.ToGRPCMessage().(*netmap.NetworkInfoResponse_Body)) + l.ResponseHeaders.ToMessage(m) + } + + return m +} + +func (l *NetworkInfoResponse) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.NetworkInfoResponse) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + l.body = nil + } else { + if l.body == nil { + l.body = new(NetworkInfoResponseBody) + } + + err = l.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + return l.ResponseHeaders.FromMessage(v) +} + +func (x *NetMap) ToGRPCMessage() grpc.Message { + var m *netmap.Netmap + + if x != nil { + m = new(netmap.Netmap) + + m.SetEpoch(x.epoch) + + if x.nodes != nil { + nodes := make([]netmap.NodeInfo, len(x.nodes)) + + for i := range x.nodes { + nodes[i] = *x.nodes[i].ToGRPCMessage().(*netmap.NodeInfo) + } + + m.SetNodes(nodes) + } + } + + return m +} + +func (x *NetMap) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.Netmap) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + nodes := v.GetNodes() + if nodes == nil { + x.nodes = nil + } else { + x.nodes = make([]NodeInfo, len(nodes)) + + for i := range nodes { + err = x.nodes[i].FromGRPCMessage(&nodes[i]) + if err != nil { + return err + } + } + } + + x.epoch = v.GetEpoch() + + return nil +} + +func (x *SnapshotRequestBody) ToGRPCMessage() grpc.Message { + var m *netmap.NetmapSnapshotRequest_Body + + if x != nil { + m = new(netmap.NetmapSnapshotRequest_Body) + } + + return m +} + +func (x *SnapshotRequestBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.NetmapSnapshotRequest_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + return nil +} + +func (x *SnapshotRequest) ToGRPCMessage() grpc.Message { + var m *netmap.NetmapSnapshotRequest + + if x != nil { + m = new(netmap.NetmapSnapshotRequest) + + m.SetBody(x.body.ToGRPCMessage().(*netmap.NetmapSnapshotRequest_Body)) + x.RequestHeaders.ToMessage(m) + } + + return m +} + +func (x *SnapshotRequest) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.NetmapSnapshotRequest) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + x.body = nil + } else { + if x.body == nil { + x.body = new(SnapshotRequestBody) + } + + err = x.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + return x.RequestHeaders.FromMessage(v) +} + +func (x *SnapshotResponseBody) ToGRPCMessage() grpc.Message { + var m *netmap.NetmapSnapshotResponse_Body + + if x != nil { + m = new(netmap.NetmapSnapshotResponse_Body) + + m.SetNetmap(x.netMap.ToGRPCMessage().(*netmap.Netmap)) + } + + return m +} + +func (x *SnapshotResponseBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.NetmapSnapshotResponse_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + netMap := v.GetNetmap() + if netMap == nil { + x.netMap = nil + } else { + if x.netMap == nil { + x.netMap = new(NetMap) + } + + err = x.netMap.FromGRPCMessage(netMap) + } + + return err +} + +func (x *SnapshotResponse) ToGRPCMessage() grpc.Message { + var m *netmap.NetmapSnapshotResponse + + if x != nil { + m = new(netmap.NetmapSnapshotResponse) + + m.SetBody(x.body.ToGRPCMessage().(*netmap.NetmapSnapshotResponse_Body)) + x.ResponseHeaders.ToMessage(m) + } + + return m +} + +func (x *SnapshotResponse) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*netmap.NetmapSnapshotResponse) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + x.body = nil + } else { + if x.body == nil { + x.body = new(SnapshotResponseBody) + } + + err = x.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + return x.ResponseHeaders.FromMessage(v) +} diff --git a/api/netmap/grpc/service_frostfs.pb.go b/api/netmap/grpc/service_frostfs.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..7e2d7a367dce459c5086ab87413ab1afd9f69c85 GIT binary patch literal 55007 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 NZYnE8lZSeF`Tr<=2;~3( literal 0 HcmV?d00001 diff --git a/api/netmap/grpc/service_frostfs_fuzz.go b/api/netmap/grpc/service_frostfs_fuzz.go new file mode 100644 index 0000000..ebb59bc --- /dev/null +++ b/api/netmap/grpc/service_frostfs_fuzz.go @@ -0,0 +1,121 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package netmap + +func DoFuzzProtoLocalNodeInfoRequest(data []byte) int { + msg := new(LocalNodeInfoRequest) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONLocalNodeInfoRequest(data []byte) int { + msg := new(LocalNodeInfoRequest) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoLocalNodeInfoResponse(data []byte) int { + msg := new(LocalNodeInfoResponse) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONLocalNodeInfoResponse(data []byte) int { + msg := new(LocalNodeInfoResponse) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoNetworkInfoRequest(data []byte) int { + msg := new(NetworkInfoRequest) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONNetworkInfoRequest(data []byte) int { + msg := new(NetworkInfoRequest) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoNetworkInfoResponse(data []byte) int { + msg := new(NetworkInfoResponse) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONNetworkInfoResponse(data []byte) int { + msg := new(NetworkInfoResponse) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoNetmapSnapshotRequest(data []byte) int { + msg := new(NetmapSnapshotRequest) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONNetmapSnapshotRequest(data []byte) int { + msg := new(NetmapSnapshotRequest) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoNetmapSnapshotResponse(data []byte) int { + msg := new(NetmapSnapshotResponse) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONNetmapSnapshotResponse(data []byte) int { + msg := new(NetmapSnapshotResponse) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} diff --git a/api/netmap/grpc/service_frostfs_test.go b/api/netmap/grpc/service_frostfs_test.go new file mode 100644 index 0000000..5c9035f --- /dev/null +++ b/api/netmap/grpc/service_frostfs_test.go @@ -0,0 +1,71 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package netmap + +import ( + testing "testing" +) + +func FuzzProtoLocalNodeInfoRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoLocalNodeInfoRequest(data) + }) +} +func FuzzJSONLocalNodeInfoRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONLocalNodeInfoRequest(data) + }) +} +func FuzzProtoLocalNodeInfoResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoLocalNodeInfoResponse(data) + }) +} +func FuzzJSONLocalNodeInfoResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONLocalNodeInfoResponse(data) + }) +} +func FuzzProtoNetworkInfoRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoNetworkInfoRequest(data) + }) +} +func FuzzJSONNetworkInfoRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONNetworkInfoRequest(data) + }) +} +func FuzzProtoNetworkInfoResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoNetworkInfoResponse(data) + }) +} +func FuzzJSONNetworkInfoResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONNetworkInfoResponse(data) + }) +} +func FuzzProtoNetmapSnapshotRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoNetmapSnapshotRequest(data) + }) +} +func FuzzJSONNetmapSnapshotRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONNetmapSnapshotRequest(data) + }) +} +func FuzzProtoNetmapSnapshotResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoNetmapSnapshotResponse(data) + }) +} +func FuzzJSONNetmapSnapshotResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONNetmapSnapshotResponse(data) + }) +} diff --git a/api/netmap/grpc/service_grpc.pb.go b/api/netmap/grpc/service_grpc.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..7deee56c6921a5cea59edf31d3c08ae2ec59b27e GIT binary patch literal 9148 zcmeHNZEqX75&rD`6|4%Rk|D3s6vY7!f+A4ttI&%bSWdqbg+p_>(!#6d9?6wX2>jps z47n?DrM0bVoF+gMH$+chh-vPzubyOWtZndwr* z?A;~1xV&a(?mzj{UvnPs5F7EhDGA|NE*`ie1vVL?VRAJ?Bmi6i%deIRnV7-}A zvs}hAmGfd2D?M|HF)ZM;d1!p(Mj>S^x7EX9ez+G6BJ$#To*9PUoC&okvs|9oY#|vp zaKi#BW)+i#skCHv&Mp3e@D}$JGe`}-r1{)tx4C4i%+4W+0Fgfp0+}VTTbUKJX0e3v z8P5u1U39MGuT`eu;q2nEH`N3m6G5_@O z{VA#if%1h5&D00w<`*S+egPOKMXGMjt2}=%?OY`n98N=P51~|XYU1Uq*hegGDHydB z0PNQ24L+@uzUx$ekorJDmvWG7TJX}$mEAS|0NZO@YXuDhS{{t^OcpLq6h7fUz5Os@ zDPqu)WDU;|eqz8m1dLqp!e#<=(yA&FChTvlGN2RvoGXLSk7SV$1B}&@FX$%(+YDKm zOAbjbQ>lq`b8Aa;IvSOCGwg&ok;_r{z8L+@^4m9w5`Xl@k5y41XsfAPAdc+1lx@=+ zC$ar>%7tW~qa%3mv$U+C2ANk0OSDh5S~xP796Lf(IoGV9?2~}2!shGP&8C?w1FQ4` zy8s(U@B(CKmfy+3EBWLB{KU)xs;~zNtGTc-n-s_y@)J!;Gek>O zmaS;RQ}FAwNiI2ca0^jQ94XRDgDRSK^r9*<;hc|sUa2AAxlw)sw2QeEcPvYhamXsC z4{4z)9Z7Um6ySt|)D2BtGLy*I6rvM$e0=$j<73u;Ib_qb@%7~L;%54BJU*LF2VNu$ z0ly_Th{;4&7&+&ZfDjK;2_cP1kpR}flP9lh{bRU+;H5mv5q!h?%_`?_C%=5WI=dNP zzJGstF@S}wRM01?*NHp^1u3%+!3TES5~CC+4MtRH4U6O0ol|3;=a(h1X2ANp6HJMm zCx=XGt@OZ|c?E;JSg`f?Tq|SGr*!I2Y@Z!ZQE5#as`X>LAU{7ZyfrN;mp%+`Aan?{ zE%8oZvE>W1aSQpDnL1xGl{zXlt~U_NQi=Ij2be5*R`vpl;52y@;Xv*{kXti$aK4Xx zN-n~KxlYMG>ry@z!k_TloIYvNbp#D*RR|>YRqcg8-Mwu8k*R~ug8<8ENr7iCI*j@( z#QkQ;zF@~4G6UAyeNj_xkdM@qO6PXHi*FqaV2+fM3IPm`c%$sGBj?qE=ecI)3~J0`4SiZoji=j z)+T}b{9ZQ~o?gT?6Of;q%C-O0l)Zv-50{-{@33u2M?_ufx+2Z@0^>8fTBe{c+KX|^ zv?1#)T!XA#;Nt3zCQ)WqRa+te!f zKpa9V3k?^v1Z6Tr)0y#vcA%#m>Mzw3R5^HvUYqM(`@Wm&lbFrce8|78 zDcBQ>%Gfh1(pu#2fTd4F_e{T%v&^7_*d>J)HoZU81*MnNTo0Mi%PyA&6loJTD(iXu z7cJd4_1EvD5l++A7HT|GxIOGUSGm8V`dAHtXIwD5X2K54mLGDjJ&h zX75T0-{XD@ByaQ}Zsk#bFUG3w>PoFdGWW&4tEqxBM_$LNdmzFJ=-eJ{pA=5pf!+zq zR*s$?FcVkhxepXA=_1hCQq=O-Fp3XD-6ZDka8!Q3 zoD7U?Aow=43=H|o%nVlgUdS1kw8PI}q>0aeL($!KRCw$+O{uWDpmM-fUf3dJg0BI> z=UFzfe=>MU#8VgLZ7R0h1pjF09%$W*z0p`@{Q)$bpmM_g4zBicMz?oW`Plw_u>plJ$-@~z4pCH$G zn#TL5#PsEX8=+E(r-@Lzy9q!^`Gl?kLWzFMe4;{l>x1F)U4)C{6lIknsiTp z?Q0Jb+LO8i*(N$4RZbqha8OqNS<)Z5wJ)9GYm|*kNyJ& CJ5~n( literal 0 HcmV?d00001 diff --git a/api/netmap/grpc/types_frostfs.pb.go b/api/netmap/grpc/types_frostfs.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..15f89594210a4b12fbe5fea083a4c6235fa802f5 GIT binary patch literal 57653 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 PA`ZQI9HkKk|Gf79;3$I^ literal 0 HcmV?d00001 diff --git a/api/object/grpc/types_frostfs.pb.go b/api/object/grpc/types_frostfs.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..6c9925cc72b4c26aa11e672d578a8a38794e8065 GIT binary patch literal 65533 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 literal 0 HcmV?d00001 diff --git a/api/object/grpc/types_frostfs_fuzz.go b/api/object/grpc/types_frostfs_fuzz.go new file mode 100644 index 0000000..8491638 --- /dev/null +++ b/api/object/grpc/types_frostfs_fuzz.go @@ -0,0 +1,102 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package object + +func DoFuzzProtoShortHeader(data []byte) int { + msg := new(ShortHeader) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONShortHeader(data []byte) int { + msg := new(ShortHeader) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoHeader(data []byte) int { + msg := new(Header) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONHeader(data []byte) int { + msg := new(Header) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoObject(data []byte) int { + msg := new(Object) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONObject(data []byte) int { + msg := new(Object) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoSplitInfo(data []byte) int { + msg := new(SplitInfo) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONSplitInfo(data []byte) int { + msg := new(SplitInfo) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoECInfo(data []byte) int { + msg := new(ECInfo) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONECInfo(data []byte) int { + msg := new(ECInfo) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} diff --git a/api/object/grpc/types_frostfs_test.go b/api/object/grpc/types_frostfs_test.go new file mode 100644 index 0000000..11825be --- /dev/null +++ b/api/object/grpc/types_frostfs_test.go @@ -0,0 +1,61 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package object + +import ( + testing "testing" +) + +func FuzzProtoShortHeader(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoShortHeader(data) + }) +} +func FuzzJSONShortHeader(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONShortHeader(data) + }) +} +func FuzzProtoHeader(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoHeader(data) + }) +} +func FuzzJSONHeader(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONHeader(data) + }) +} +func FuzzProtoObject(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoObject(data) + }) +} +func FuzzJSONObject(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONObject(data) + }) +} +func FuzzProtoSplitInfo(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoSplitInfo(data) + }) +} +func FuzzJSONSplitInfo(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONSplitInfo(data) + }) +} +func FuzzProtoECInfo(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoECInfo(data) + }) +} +func FuzzJSONECInfo(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONECInfo(data) + }) +} diff --git a/api/object/json.go b/api/object/json.go new file mode 100644 index 0000000..faef249 --- /dev/null +++ b/api/object/json.go @@ -0,0 +1,94 @@ +package object + +import ( + object "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" +) + +func (h *ShortHeader) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(h) +} + +func (h *ShortHeader) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(h, data, new(object.ShortHeader)) +} + +func (a *Attribute) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(a) +} + +func (a *Attribute) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(a, data, new(object.Header_Attribute)) +} + +func (h *SplitHeader) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(h) +} + +func (h *SplitHeader) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(h, data, new(object.Header_Split)) +} + +func (h *Header) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(h) +} + +func (h *Header) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(h, data, new(object.Header)) +} + +func (h *HeaderWithSignature) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(h) +} + +func (h *HeaderWithSignature) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(h, data, new(object.HeaderWithSignature)) +} + +func (o *Object) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(o) +} + +func (o *Object) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(o, data, new(object.Object)) +} + +func (s *SplitInfo) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(s) +} + +func (s *SplitInfo) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(s, data, new(object.SplitInfo)) +} + +func (e *ECInfo) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(e) +} + +func (e *ECInfo) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(e, data, new(object.ECInfo)) +} + +func (e *ECChunk) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(e) +} + +func (e *ECChunk) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(e, data, new(object.ECInfo_Chunk)) +} + +func (f *SearchFilter) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(f) +} + +func (f *SearchFilter) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(f, data, new(object.SearchRequest_Body_Filter)) +} + +func (r *Range) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(r) +} + +func (r *Range) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(r, data, new(object.Range)) +} diff --git a/api/object/lock.go b/api/object/lock.go new file mode 100644 index 0000000..3af06c6 --- /dev/null +++ b/api/object/lock.go @@ -0,0 +1,160 @@ +package object + +import ( + "errors" + "fmt" + + lock "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/lock/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + refsGRPC "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/util/proto" +) + +// Lock represents object Lock message from NeoFS API V2 protocol. +type Lock struct { + members []refs.ObjectID +} + +// NumberOfMembers returns length of lock list. +func (x *Lock) NumberOfMembers() int { + if x != nil { + return len(x.members) + } + + return 0 +} + +// IterateMembers passes members of the lock list to f. +func (x *Lock) IterateMembers(f func(refs.ObjectID)) { + if x != nil { + for i := range x.members { + f(x.members[i]) + } + } +} + +// SetMembers sets list of locked members. +// Arg must not be mutated for the duration of the Lock. +func (x *Lock) SetMembers(ids []refs.ObjectID) { + x.members = ids +} + +const ( + _ = iota + fNumLockMembers +) + +// StableMarshal encodes the Lock into Protocol Buffers binary format +// with direct field order. +func (x *Lock) StableMarshal(buf []byte) []byte { + if x == nil || len(x.members) == 0 { + return []byte{} + } + + if buf == nil { + buf = make([]byte, x.StableSize()) + } + + var offset int + + for i := range x.members { + offset += proto.NestedStructureMarshal(fNumLockMembers, buf[offset:], &x.members[i]) + } + + return buf +} + +// StableSize size of the buffer required to write the Lock in Protocol Buffers +// binary format. +func (x *Lock) StableSize() (sz int) { + if x != nil { + for i := range x.members { + sz += proto.NestedStructureSize(fNumLockMembers, &x.members[i]) + } + } + + return +} + +// Unmarshal decodes the Lock from its Protocol Buffers binary format. +func (x *Lock) Unmarshal(data []byte) error { + return message.Unmarshal(x, data, new(lock.Lock)) +} + +func (x *Lock) ToGRPCMessage() grpc.Message { + var m *lock.Lock + + if x != nil { + m = new(lock.Lock) + + var members []refsGRPC.ObjectID + + if x.members != nil { + members = make([]refsGRPC.ObjectID, len(x.members)) + + for i := range x.members { + members[i] = *x.members[i].ToGRPCMessage().(*refsGRPC.ObjectID) + } + } + + m.SetMembers(members) + } + + return m +} + +func (x *Lock) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*lock.Lock) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + members := v.GetMembers() + if members == nil { + x.members = nil + } else { + x.members = make([]refs.ObjectID, len(members)) + var err error + + for i := range x.members { + err = x.members[i].FromGRPCMessage(&members[i]) + if err != nil { + return err + } + } + } + + return nil +} + +// WriteLock writes Lock to the Object as a payload content. +// The object must not be nil. +func WriteLock(obj *Object, lock Lock) { + hdr := obj.GetHeader() + if hdr == nil { + hdr = new(Header) + obj.SetHeader(hdr) + } + + hdr.SetObjectType(TypeLock) + + payload := lock.StableMarshal(nil) + obj.SetPayload(payload) +} + +// ReadLock reads Lock from the Object payload content. +func ReadLock(lock *Lock, obj Object) error { + payload := obj.GetPayload() + if len(payload) == 0 { + return errors.New("empty payload") + } + + err := lock.Unmarshal(payload) + if err != nil { + return fmt.Errorf("decode lock content from payload: %w", err) + } + + return nil +} diff --git a/api/object/lock_test.go b/api/object/lock_test.go new file mode 100644 index 0000000..2515723 --- /dev/null +++ b/api/object/lock_test.go @@ -0,0 +1,26 @@ +package object_test + +import ( + "testing" + + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object" + objecttest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object/test" + "github.com/stretchr/testify/require" +) + +func TestLockRW(t *testing.T) { + var l object.Lock + var obj object.Object + + require.Error(t, object.ReadLock(&l, obj)) + + l = *objecttest.GenerateLock(false) + + object.WriteLock(&obj, l) + + var l2 object.Lock + + require.NoError(t, object.ReadLock(&l2, obj)) + + require.Equal(t, l, l2) +} diff --git a/api/object/marshal.go b/api/object/marshal.go new file mode 100644 index 0000000..82e265b --- /dev/null +++ b/api/object/marshal.go @@ -0,0 +1,1428 @@ +package object + +import ( + object "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/util/proto" +) + +const ( + shortHdrVersionField = 1 + shortHdrEpochField = 2 + shortHdrOwnerField = 3 + shortHdrObjectTypeField = 4 + shortHdrPayloadLength = 5 + shortHdrHashField = 6 + shortHdrHomoHashField = 7 + + attributeKeyField = 1 + attributeValueField = 2 + + splitHdrParentField = 1 + splitHdrPreviousField = 2 + splitHdrParentSignatureField = 3 + splitHdrParentHeaderField = 4 + splitHdrChildrenField = 5 + splitHdrSplitIDField = 6 + + ecHdrParentField = 1 + ecHdrIndexField = 2 + ecHdrTotalField = 3 + ecHdrHeaderLengthField = 4 + ecHdrHeaderField = 5 + ecHdrParentSplitID = 6 + ecHdrParentSplitParentID = 7 + ecHdrParentAttributes = 8 + + hdrVersionField = 1 + hdrContainerIDField = 2 + hdrOwnerIDField = 3 + hdrEpochField = 4 + hdrPayloadLengthField = 5 + hdrPayloadHashField = 6 + hdrObjectTypeField = 7 + hdrHomomorphicHashField = 8 + hdrSessionTokenField = 9 + hdrAttributesField = 10 + hdrSplitField = 11 + hdrECField = 12 + + hdrWithSigHeaderField = 1 + hdrWithSigSignatureField = 2 + + objIDField = 1 + objSignatureField = 2 + objHeaderField = 3 + objPayloadField = 4 + + splitInfoSplitIDField = 1 + splitInfoLastPartField = 2 + splitInfoLinkField = 3 + + ecInfoChunksField = 1 + + ecChunkIDField = 1 + ecChunkIndexField = 2 + ecChunkTotalField = 3 + + getReqBodyAddressField = 1 + getReqBodyRawFlagField = 2 + + getRespInitObjectIDField = 1 + getRespInitSignatureField = 2 + getRespInitHeaderField = 3 + + getRespBodyInitField = 1 + getRespBodyChunkField = 2 + getRespBodySplitInfoField = 3 + getRespBodyECInfoField = 4 + + putReqInitObjectIDField = 1 + putReqInitSignatureField = 2 + putReqInitHeaderField = 3 + putReqInitCopiesNumField = 4 + + putReqBodyInitField = 1 + putReqBodyChunkField = 2 + + putRespBodyObjectIDField = 1 + + deleteReqBodyAddressField = 1 + + deleteRespBodyTombstoneFNum = 1 + + headReqBodyAddressField = 1 + headReqBodyMainFlagField = 2 + headReqBodyRawFlagField = 3 + + headRespBodyHeaderField = 1 + headRespBodyShortHeaderField = 2 + headRespBodySplitInfoField = 3 + headRespBodyECInfoField = 4 + + searchFilterMatchField = 1 + searchFilterNameField = 2 + searchFilterValueField = 3 + + searchReqBodyContainerIDField = 1 + searchReqBodyVersionField = 2 + searchReqBodyFiltersField = 3 + + searchRespBodyObjectIDsField = 1 + + rangeOffsetField = 1 + rangeLengthField = 2 + + getRangeReqBodyAddressField = 1 + getRangeReqBodyRangeField = 2 + getRangeReqBodyRawField = 3 + + getRangeRespChunkField = 1 + getRangeRespSplitInfoField = 2 + getRangeRespECInfoField = 3 + + getRangeHashReqBodyAddressField = 1 + getRangeHashReqBodyRangesField = 2 + getRangeHashReqBodySaltField = 3 + getRangeHashReqBodyTypeField = 4 + + getRangeHashRespBodyTypeField = 1 + getRangeHashRespBodyHashListField = 2 + + putSingleReqObjectField = 1 + putSingleReqCopiesNumberField = 2 + + patchRequestBodyPatchRangeField = 1 + patchRequestBodyPatchChunkField = 2 + + patchRequestBodyAddrField = 1 + patchRequestBodyNewAttrsField = 2 + patchRequestBodyReplaceAttrField = 3 + patchRequestBodyPatchField = 4 + + patchResponseBodyObjectIDField = 1 +) + +func (h *ShortHeader) StableMarshal(buf []byte) []byte { + if h == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, h.StableSize()) + } + + var offset int + + offset += proto.NestedStructureMarshal(shortHdrVersionField, buf[offset:], h.version) + offset += proto.UInt64Marshal(shortHdrEpochField, buf[offset:], h.creatEpoch) + offset += proto.NestedStructureMarshal(shortHdrOwnerField, buf[offset:], h.ownerID) + offset += proto.EnumMarshal(shortHdrObjectTypeField, buf[offset:], int32(h.typ)) + offset += proto.UInt64Marshal(shortHdrPayloadLength, buf[offset:], h.payloadLen) + offset += proto.NestedStructureMarshal(shortHdrHashField, buf[offset:], h.payloadHash) + proto.NestedStructureMarshal(shortHdrHomoHashField, buf[offset:], h.homoHash) + + return buf +} + +func (h *ShortHeader) StableSize() (size int) { + if h == nil { + return 0 + } + + size += proto.NestedStructureSize(shortHdrVersionField, h.version) + size += proto.UInt64Size(shortHdrEpochField, h.creatEpoch) + size += proto.NestedStructureSize(shortHdrOwnerField, h.ownerID) + size += proto.EnumSize(shortHdrObjectTypeField, int32(h.typ)) + size += proto.UInt64Size(shortHdrPayloadLength, h.payloadLen) + size += proto.NestedStructureSize(shortHdrHashField, h.payloadHash) + size += proto.NestedStructureSize(shortHdrHomoHashField, h.homoHash) + + return size +} + +func (h *ShortHeader) Unmarshal(data []byte) error { + return message.Unmarshal(h, data, new(object.ShortHeader)) +} + +func (a *Attribute) StableMarshal(buf []byte) []byte { + if a == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, a.StableSize()) + } + + var offset int + + offset += proto.StringMarshal(attributeKeyField, buf[offset:], a.key) + proto.StringMarshal(attributeValueField, buf[offset:], a.val) + + return buf +} + +func (a *Attribute) StableSize() (size int) { + if a == nil { + return 0 + } + + size += proto.StringSize(shortHdrVersionField, a.key) + size += proto.StringSize(shortHdrEpochField, a.val) + + return size +} + +func (a *Attribute) Unmarshal(data []byte) error { + return message.Unmarshal(a, data, new(object.Header_Attribute)) +} + +func (h *SplitHeader) StableMarshal(buf []byte) []byte { + if h == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, h.StableSize()) + } + + var offset int + + offset += proto.NestedStructureMarshal(splitHdrParentField, buf[offset:], h.par) + offset += proto.NestedStructureMarshal(splitHdrPreviousField, buf[offset:], h.prev) + offset += proto.NestedStructureMarshal(splitHdrParentSignatureField, buf[offset:], h.parSig) + offset += proto.NestedStructureMarshal(splitHdrParentHeaderField, buf[offset:], h.parHdr) + offset += refs.ObjectIDNestedListMarshal(splitHdrChildrenField, buf[offset:], h.children) + proto.BytesMarshal(splitHdrSplitIDField, buf[offset:], h.splitID) + + return buf +} + +func (h *SplitHeader) StableSize() (size int) { + if h == nil { + return 0 + } + + size += proto.NestedStructureSize(splitHdrParentField, h.par) + size += proto.NestedStructureSize(splitHdrPreviousField, h.prev) + size += proto.NestedStructureSize(splitHdrParentSignatureField, h.parSig) + size += proto.NestedStructureSize(splitHdrParentHeaderField, h.parHdr) + size += refs.ObjectIDNestedListSize(splitHdrChildrenField, h.children) + size += proto.BytesSize(splitHdrSplitIDField, h.splitID) + + return size +} + +func (h *SplitHeader) Unmarshal(data []byte) error { + return message.Unmarshal(h, data, new(object.Header_Split)) +} + +func (h *ECHeader) StableMarshal(buf []byte) []byte { + if h == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, h.StableSize()) + } + + var offset int + + offset += proto.NestedStructureMarshal(ecHdrParentField, buf[offset:], h.Parent) + offset += proto.UInt32Marshal(ecHdrIndexField, buf[offset:], h.Index) + offset += proto.UInt32Marshal(ecHdrTotalField, buf[offset:], h.Total) + offset += proto.UInt32Marshal(ecHdrHeaderLengthField, buf[offset:], h.HeaderLength) + offset += proto.BytesMarshal(ecHdrHeaderField, buf[offset:], h.Header) + offset += proto.BytesMarshal(ecHdrParentSplitID, buf[offset:], h.ParentSplitID) + offset += proto.NestedStructureMarshal(ecHdrParentSplitParentID, buf[offset:], h.ParentSplitParentID) + for i := range h.ParentAttributes { + offset += proto.NestedStructureMarshal(ecHdrParentAttributes, buf[offset:], &h.ParentAttributes[i]) + } + return buf +} + +func (h *ECHeader) StableSize() (size int) { + if h == nil { + return 0 + } + + size += proto.NestedStructureSize(ecHdrParentField, h.Parent) + size += proto.UInt32Size(ecHdrIndexField, h.Index) + size += proto.UInt32Size(ecHdrTotalField, h.Total) + size += proto.UInt32Size(ecHdrHeaderLengthField, h.HeaderLength) + size += proto.BytesSize(ecHdrHeaderField, h.Header) + size += proto.BytesSize(ecHdrParentSplitID, h.ParentSplitID) + size += proto.NestedStructureSize(ecHdrParentSplitParentID, h.ParentSplitParentID) + for i := range h.ParentAttributes { + size += proto.NestedStructureSize(ecHdrParentAttributes, &h.ParentAttributes[i]) + } + + return size +} + +func (h *ECHeader) Unmarshal(data []byte) error { + return message.Unmarshal(h, data, new(object.Header_EC)) +} + +func (h *Header) StableMarshal(buf []byte) []byte { + if h == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, h.StableSize()) + } + + var offset int + + offset += proto.NestedStructureMarshal(hdrVersionField, buf[offset:], h.version) + offset += proto.NestedStructureMarshal(hdrContainerIDField, buf[offset:], h.cid) + offset += proto.NestedStructureMarshal(hdrOwnerIDField, buf[offset:], h.ownerID) + offset += proto.UInt64Marshal(hdrEpochField, buf[offset:], h.creatEpoch) + offset += proto.UInt64Marshal(hdrPayloadLengthField, buf[offset:], h.payloadLen) + offset += proto.NestedStructureMarshal(hdrPayloadHashField, buf[offset:], h.payloadHash) + offset += proto.EnumMarshal(hdrObjectTypeField, buf[offset:], int32(h.typ)) + offset += proto.NestedStructureMarshal(hdrHomomorphicHashField, buf[offset:], h.homoHash) + offset += proto.NestedStructureMarshal(hdrSessionTokenField, buf[offset:], h.sessionToken) + + for i := range h.attr { + offset += proto.NestedStructureMarshal(hdrAttributesField, buf[offset:], &h.attr[i]) + } + + proto.NestedStructureMarshal(hdrSplitField, buf[offset:], h.split) + proto.NestedStructureMarshal(hdrECField, buf[offset:], h.ec) + + return buf +} + +func (h *Header) StableSize() (size int) { + if h == nil { + return 0 + } + + size += proto.NestedStructureSize(hdrVersionField, h.version) + size += proto.NestedStructureSize(hdrContainerIDField, h.cid) + size += proto.NestedStructureSize(hdrOwnerIDField, h.ownerID) + size += proto.UInt64Size(hdrEpochField, h.creatEpoch) + size += proto.UInt64Size(hdrPayloadLengthField, h.payloadLen) + size += proto.NestedStructureSize(hdrPayloadHashField, h.payloadHash) + size += proto.EnumSize(hdrObjectTypeField, int32(h.typ)) + size += proto.NestedStructureSize(hdrHomomorphicHashField, h.homoHash) + size += proto.NestedStructureSize(hdrSessionTokenField, h.sessionToken) + for i := range h.attr { + size += proto.NestedStructureSize(hdrAttributesField, &h.attr[i]) + } + size += proto.NestedStructureSize(hdrSplitField, h.split) + size += proto.NestedStructureSize(hdrECField, h.ec) + + return size +} + +func (h *Header) Unmarshal(data []byte) error { + return message.Unmarshal(h, data, new(object.Header)) +} + +func (h *HeaderWithSignature) StableMarshal(buf []byte) []byte { + if h == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, h.StableSize()) + } + + var offset int + + offset += proto.NestedStructureMarshal(hdrWithSigHeaderField, buf[offset:], h.header) + proto.NestedStructureMarshal(hdrWithSigSignatureField, buf[offset:], h.signature) + + return buf +} + +func (h *HeaderWithSignature) StableSize() (size int) { + if h == nil { + return 0 + } + + size += proto.NestedStructureSize(hdrVersionField, h.header) + size += proto.NestedStructureSize(hdrContainerIDField, h.signature) + + return size +} + +func (h *HeaderWithSignature) Unmarshal(data []byte) error { + return message.Unmarshal(h, data, new(object.HeaderWithSignature)) +} + +func (o *Object) StableMarshal(buf []byte) []byte { + if o == nil { + return []byte{} + } + + if o.marshalData != nil { + if buf == nil { + return o.marshalData + } + copy(buf, o.marshalData) + return buf + } + + if buf == nil { + buf = make([]byte, o.StableSize()) + } + + var offset int + + offset += proto.NestedStructureMarshal(objIDField, buf[offset:], o.objectID) + offset += proto.NestedStructureMarshal(objSignatureField, buf[offset:], o.idSig) + offset += proto.NestedStructureMarshal(objHeaderField, buf[offset:], o.header) + proto.BytesMarshal(objPayloadField, buf[offset:], o.payload) + + return buf +} + +// SetMarshalData sets marshal data to reduce memory allocations. +// +// It is unsafe to modify/copy object data after setting marshal data. +func (o *Object) SetMarshalData(data []byte) { + if o == nil { + return + } + o.marshalData = data +} + +func (o *Object) StableSize() (size int) { + if o == nil { + return 0 + } + + size += proto.NestedStructureSize(objIDField, o.objectID) + size += proto.NestedStructureSize(objSignatureField, o.idSig) + size += proto.NestedStructureSize(objHeaderField, o.header) + size += proto.BytesSize(objPayloadField, o.payload) + + return size +} + +func (o *Object) Unmarshal(data []byte) error { + return message.Unmarshal(o, data, new(object.Object)) +} + +func (s *SplitInfo) StableMarshal(buf []byte) []byte { + if s == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, s.StableSize()) + } + + var offset int + + offset += proto.BytesMarshal(splitInfoSplitIDField, buf[offset:], s.splitID) + offset += proto.NestedStructureMarshal(splitInfoLastPartField, buf[offset:], s.lastPart) + proto.NestedStructureMarshal(splitInfoLinkField, buf[offset:], s.link) + + return buf +} + +func (s *SplitInfo) StableSize() (size int) { + if s == nil { + return 0 + } + + size += proto.BytesSize(splitInfoSplitIDField, s.splitID) + size += proto.NestedStructureSize(splitInfoLastPartField, s.lastPart) + size += proto.NestedStructureSize(splitInfoLinkField, s.link) + + return size +} + +func (s *SplitInfo) Unmarshal(data []byte) error { + return message.Unmarshal(s, data, new(object.SplitInfo)) +} + +func (e *ECInfo) StableMarshal(buf []byte) []byte { + if e == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, e.StableSize()) + } + + var offset int + + for i := range e.Chunks { + offset += proto.NestedStructureMarshal(ecInfoChunksField, buf[offset:], &e.Chunks[i]) + } + + return buf +} + +func (e *ECInfo) StableSize() (size int) { + if e == nil { + return 0 + } + + for i := range e.Chunks { + size += proto.NestedStructureSize(ecInfoChunksField, &e.Chunks[i]) + } + + return size +} + +func (e *ECInfo) Unmarshal(data []byte) error { + return message.Unmarshal(e, data, new(object.ECInfo)) +} + +func (c *ECChunk) StableMarshal(buf []byte) []byte { + if c == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, c.StableSize()) + } + + var offset int + + offset += proto.NestedStructureMarshal(ecChunkIDField, buf[offset:], &c.ID) + offset += proto.UInt32Marshal(ecChunkIndexField, buf[offset:], c.Index) + proto.UInt32Marshal(ecChunkTotalField, buf[offset:], c.Total) + + return buf +} + +func (c *ECChunk) StableSize() (size int) { + if c == nil { + return 0 + } + + size += proto.NestedStructureSize(ecChunkIDField, &c.ID) + size += proto.UInt32Size(ecChunkIndexField, c.Index) + size += proto.UInt32Size(ecChunkTotalField, c.Total) + + return size +} + +func (c *ECChunk) Unmarshal(data []byte) error { + return message.Unmarshal(c, data, new(object.ECInfo_Chunk)) +} + +func (r *GetRequestBody) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var offset int + + offset += proto.NestedStructureMarshal(getReqBodyAddressField, buf[offset:], r.addr) + proto.BoolMarshal(getReqBodyRawFlagField, buf[offset:], r.raw) + + return buf +} + +func (r *GetRequestBody) StableSize() (size int) { + if r == nil { + return 0 + } + + size += proto.NestedStructureSize(getReqBodyAddressField, r.addr) + size += proto.BoolSize(getReqBodyRawFlagField, r.raw) + + return size +} + +func (r *GetRequestBody) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.GetRequest_Body)) +} + +func (r *GetObjectPartInit) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var offset int + + offset += proto.NestedStructureMarshal(getRespInitObjectIDField, buf[offset:], r.id) + offset += proto.NestedStructureMarshal(getRespInitSignatureField, buf[offset:], r.sig) + proto.NestedStructureMarshal(getRespInitHeaderField, buf[offset:], r.hdr) + + return buf +} + +func (r *GetObjectPartInit) StableSize() (size int) { + if r == nil { + return 0 + } + + size += proto.NestedStructureSize(getRespInitObjectIDField, r.id) + size += proto.NestedStructureSize(getRespInitSignatureField, r.sig) + size += proto.NestedStructureSize(getRespInitHeaderField, r.hdr) + + return size +} + +func (r *GetObjectPartInit) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.GetResponse_Body_Init)) +} + +func (r *GetResponseBody) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + switch v := r.objPart.(type) { + case nil: + case *GetObjectPartInit: + proto.NestedStructureMarshal(getRespBodyInitField, buf, v) + case *GetObjectPartChunk: + if v != nil { + proto.BytesMarshal(getRespBodyChunkField, buf, v.chunk) + } + case *SplitInfo: + proto.NestedStructureMarshal(getRespBodySplitInfoField, buf, v) + case *ECInfo: + proto.NestedStructureMarshal(getRespBodyECInfoField, buf, v) + default: + panic("unknown one of object get response body type") + } + + return buf +} + +func (r *GetResponseBody) StableSize() (size int) { + if r == nil { + return 0 + } + + switch v := r.objPart.(type) { + case nil: + case *GetObjectPartInit: + size += proto.NestedStructureSize(getRespBodyInitField, v) + case *GetObjectPartChunk: + if v != nil { + size += proto.BytesSize(getRespBodyChunkField, v.chunk) + } + case *SplitInfo: + size += proto.NestedStructureSize(getRespBodySplitInfoField, v) + case *ECInfo: + size += proto.NestedStructureSize(getRespBodyECInfoField, v) + default: + panic("unknown one of object get response body type") + } + + return +} + +func (r *GetResponseBody) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.GetResponse_Body)) +} + +func (r *PutObjectPartInit) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var offset int + + offset += proto.NestedStructureMarshal(putReqInitObjectIDField, buf[offset:], r.id) + offset += proto.NestedStructureMarshal(putReqInitSignatureField, buf[offset:], r.sig) + offset += proto.NestedStructureMarshal(putReqInitHeaderField, buf[offset:], r.hdr) + proto.RepeatedUInt32Marshal(putReqInitCopiesNumField, buf[offset:], r.copyNum) + + return buf +} + +func (r *PutObjectPartInit) StableSize() (size int) { + if r == nil { + return 0 + } + + size += proto.NestedStructureSize(putReqInitObjectIDField, r.id) + size += proto.NestedStructureSize(putReqInitSignatureField, r.sig) + size += proto.NestedStructureSize(putReqInitHeaderField, r.hdr) + + arrSize, _ := proto.RepeatedUInt32Size(putReqInitCopiesNumField, r.copyNum) + size += arrSize + + return size +} + +func (r *PutObjectPartInit) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.PutRequest_Body_Init)) +} + +func (r *PutRequestBody) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + switch v := r.objPart.(type) { + case nil: + case *PutObjectPartInit: + proto.NestedStructureMarshal(putReqBodyInitField, buf, v) + case *PutObjectPartChunk: + if v != nil { + proto.BytesMarshal(putReqBodyChunkField, buf, v.chunk) + } + default: + panic("unknown one of object put request body type") + } + + return buf +} + +func (r *PutRequestBody) StableSize() (size int) { + if r == nil { + return 0 + } + + switch v := r.objPart.(type) { + case nil: + case *PutObjectPartInit: + size += proto.NestedStructureSize(putReqBodyInitField, v) + case *PutObjectPartChunk: + if v != nil { + size += proto.BytesSize(putReqBodyChunkField, v.chunk) + } + default: + panic("unknown one of object get response body type") + } + + return size +} + +func (r *PutRequestBody) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.PutRequest_Body)) +} + +func (r *PutResponseBody) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + proto.NestedStructureMarshal(putRespBodyObjectIDField, buf, r.id) + + return buf +} + +func (r *PutResponseBody) StableSize() (size int) { + if r == nil { + return 0 + } + + size += proto.NestedStructureSize(putRespBodyObjectIDField, r.id) + + return size +} + +func (r *PutResponseBody) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.PutResponse_Body)) +} + +func (r *DeleteRequestBody) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + proto.NestedStructureMarshal(deleteReqBodyAddressField, buf, r.addr) + + return buf +} + +func (r *DeleteRequestBody) StableSize() (size int) { + if r == nil { + return 0 + } + + size += proto.NestedStructureSize(deleteReqBodyAddressField, r.addr) + + return size +} + +func (r *DeleteRequestBody) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.DeleteRequest_Body)) +} + +func (r *DeleteResponseBody) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + proto.NestedStructureMarshal(deleteRespBodyTombstoneFNum, buf, r.tombstone) + + return buf +} + +func (r *DeleteResponseBody) StableSize() (size int) { + if r == nil { + return 0 + } + + size += proto.NestedStructureSize(deleteRespBodyTombstoneFNum, r.tombstone) + + return size +} + +func (r *DeleteResponseBody) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.DeleteResponse_Body)) +} + +func (r *HeadRequestBody) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var offset int + + offset += proto.NestedStructureMarshal(headReqBodyAddressField, buf[offset:], r.addr) + offset += proto.BoolMarshal(headReqBodyMainFlagField, buf[offset:], r.mainOnly) + proto.BoolMarshal(headReqBodyRawFlagField, buf[offset:], r.raw) + + return buf +} + +func (r *HeadRequestBody) StableSize() (size int) { + if r == nil { + return 0 + } + + size += proto.NestedStructureSize(headReqBodyAddressField, r.addr) + size += proto.BoolSize(headReqBodyMainFlagField, r.mainOnly) + size += proto.BoolSize(headReqBodyRawFlagField, r.raw) + + return size +} + +func (r *HeadRequestBody) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.HeadRequest_Body)) +} + +func (r *HeadResponseBody) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + switch v := r.hdrPart.(type) { + case nil: + case *HeaderWithSignature: + if v != nil { + proto.NestedStructureMarshal(headRespBodyHeaderField, buf, v) + } + case *ShortHeader: + if v != nil { + proto.NestedStructureMarshal(headRespBodyShortHeaderField, buf, v) + } + case *SplitInfo: + if v != nil { + proto.NestedStructureMarshal(headRespBodySplitInfoField, buf, v) + } + case *ECInfo: + if v != nil { + proto.NestedStructureMarshal(headRespBodyECInfoField, buf, v) + } + default: + panic("unknown one of object put request body type") + } + + return buf +} + +func (r *HeadResponseBody) StableSize() (size int) { + if r == nil { + return 0 + } + + switch v := r.hdrPart.(type) { + case nil: + case *HeaderWithSignature: + if v != nil { + size += proto.NestedStructureSize(headRespBodyHeaderField, v) + } + case *ShortHeader: + if v != nil { + size += proto.NestedStructureSize(headRespBodyShortHeaderField, v) + } + case *SplitInfo: + if v != nil { + size += proto.NestedStructureSize(headRespBodySplitInfoField, v) + } + case *ECInfo: + if v != nil { + size += proto.NestedStructureSize(headRespBodyECInfoField, v) + } + default: + panic("unknown one of object put request body type") + } + + return +} + +func (r *HeadResponseBody) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.HeadResponse_Body)) +} + +func (f *SearchFilter) StableMarshal(buf []byte) []byte { + if f == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, f.StableSize()) + } + + var offset int + + offset += proto.EnumMarshal(searchFilterMatchField, buf[offset:], int32(f.matchType)) + offset += proto.StringMarshal(searchFilterNameField, buf[offset:], f.key) + proto.StringMarshal(searchFilterValueField, buf[offset:], f.val) + + return buf +} + +func (f *SearchFilter) StableSize() (size int) { + if f == nil { + return 0 + } + + size += proto.EnumSize(searchFilterMatchField, int32(f.matchType)) + size += proto.StringSize(searchFilterNameField, f.key) + size += proto.StringSize(searchFilterValueField, f.val) + + return size +} + +func (f *SearchFilter) Unmarshal(data []byte) error { + return message.Unmarshal(f, data, new(object.SearchRequest_Body_Filter)) +} + +func (r *SearchRequestBody) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var offset int + + offset += proto.NestedStructureMarshal(searchReqBodyContainerIDField, buf[offset:], r.cid) + offset += proto.UInt32Marshal(searchReqBodyVersionField, buf[offset:], r.version) + + for i := range r.filters { + offset += proto.NestedStructureMarshal(searchReqBodyFiltersField, buf[offset:], &r.filters[i]) + } + + return buf +} + +func (r *SearchRequestBody) StableSize() (size int) { + if r == nil { + return 0 + } + + size += proto.NestedStructureSize(searchReqBodyContainerIDField, r.cid) + size += proto.UInt32Size(searchReqBodyVersionField, r.version) + + for i := range r.filters { + size += proto.NestedStructureSize(searchReqBodyFiltersField, &r.filters[i]) + } + + return size +} + +func (r *SearchRequestBody) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.SearchRequest_Body)) +} + +func (r *SearchResponseBody) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var offset int + + refs.ObjectIDNestedListMarshal(searchRespBodyObjectIDsField, buf[offset:], r.idList) + + return buf +} + +func (r *SearchResponseBody) StableSize() (size int) { + if r == nil { + return 0 + } + + size += refs.ObjectIDNestedListSize(searchRespBodyObjectIDsField, r.idList) + + return size +} + +func (r *SearchResponseBody) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.SearchResponse_Body)) +} + +func (r *Range) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var offset int + + offset += proto.UInt64Marshal(rangeOffsetField, buf[offset:], r.off) + proto.UInt64Marshal(rangeLengthField, buf[offset:], r.len) + + return buf +} + +func (r *Range) StableSize() (size int) { + if r == nil { + return 0 + } + + size += proto.UInt64Size(rangeOffsetField, r.off) + size += proto.UInt64Size(rangeLengthField, r.len) + + return size +} + +func (r *Range) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.Range)) +} + +func (r *GetRangeRequestBody) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var offset int + + offset += proto.NestedStructureMarshal(getRangeReqBodyAddressField, buf[offset:], r.addr) + offset += proto.NestedStructureMarshal(getRangeReqBodyRangeField, buf[offset:], r.rng) + proto.BoolMarshal(getRangeReqBodyRawField, buf[offset:], r.raw) + + return buf +} + +func (r *GetRangeRequestBody) StableSize() (size int) { + if r == nil { + return 0 + } + + size += proto.NestedStructureSize(getRangeReqBodyAddressField, r.addr) + size += proto.NestedStructureSize(getRangeReqBodyRangeField, r.rng) + size += proto.BoolSize(getRangeReqBodyRawField, r.raw) + + return size +} + +func (r *GetRangeRequestBody) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.GetRangeRequest_Body)) +} + +func (r *GetRangeResponseBody) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + switch v := r.rngPart.(type) { + case nil: + case *GetRangePartChunk: + if v != nil { + proto.BytesMarshal(getRangeRespChunkField, buf, v.chunk) + } + case *SplitInfo: + if v != nil { + proto.NestedStructureMarshal(getRangeRespSplitInfoField, buf, v) + } + case *ECInfo: + if v != nil { + proto.NestedStructureMarshal(getRangeRespECInfoField, buf, v) + } + default: + panic("unknown one of object get range request body type") + } + + return buf +} + +func (r *GetRangeResponseBody) StableSize() (size int) { + if r == nil { + return 0 + } + + switch v := r.rngPart.(type) { + case nil: + case *GetRangePartChunk: + if v != nil { + size += proto.BytesSize(getRangeRespChunkField, v.chunk) + } + case *SplitInfo: + if v != nil { + size = proto.NestedStructureSize(getRangeRespSplitInfoField, v) + } + case *ECInfo: + if v != nil { + size = proto.NestedStructureSize(getRangeRespECInfoField, v) + } + default: + panic("unknown one of object get range request body type") + } + + return +} + +func (r *GetRangeResponseBody) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.GetRangeResponse_Body)) +} + +func (r *GetRangeHashRequestBody) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var offset int + + offset += proto.NestedStructureMarshal(getRangeHashReqBodyAddressField, buf[offset:], r.addr) + + for i := range r.rngs { + offset += proto.NestedStructureMarshal(getRangeHashReqBodyRangesField, buf[offset:], &r.rngs[i]) + } + + offset += proto.BytesMarshal(getRangeHashReqBodySaltField, buf[offset:], r.salt) + proto.EnumMarshal(getRangeHashReqBodyTypeField, buf[offset:], int32(r.typ)) + + return buf +} + +func (r *GetRangeHashRequestBody) StableSize() (size int) { + if r == nil { + return 0 + } + + size += proto.NestedStructureSize(getRangeHashReqBodyAddressField, r.addr) + + for i := range r.rngs { + size += proto.NestedStructureSize(getRangeHashReqBodyRangesField, &r.rngs[i]) + } + + size += proto.BytesSize(getRangeHashReqBodySaltField, r.salt) + size += proto.EnumSize(getRangeHashReqBodyTypeField, int32(r.typ)) + + return size +} + +func (r *GetRangeHashRequestBody) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.GetRangeHashRequest_Body)) +} + +func (r *GetRangeHashResponseBody) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var offset int + + offset += proto.EnumMarshal(getRangeHashRespBodyTypeField, buf, int32(r.typ)) + proto.RepeatedBytesMarshal(getRangeHashRespBodyHashListField, buf[offset:], r.hashList) + + return buf +} + +func (r *GetRangeHashResponseBody) StableSize() (size int) { + if r == nil { + return 0 + } + + size += proto.EnumSize(getRangeHashRespBodyTypeField, int32(r.typ)) + size += proto.RepeatedBytesSize(getRangeHashRespBodyHashListField, r.hashList) + + return size +} + +func (r *GetRangeHashResponseBody) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.GetRangeHashResponse_Body)) +} + +func (r *PutSingleRequestBody) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if r.marshalData != nil { + if buf == nil { + return r.marshalData + } + copy(buf, r.marshalData) + return buf + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var offset int + offset += proto.NestedStructureMarshal(putSingleReqObjectField, buf[offset:], r.object) + proto.RepeatedUInt32Marshal(putSingleReqCopiesNumberField, buf[offset:], r.copyNum) + + return buf +} + +// SetMarshalData sets marshal data to reduce memory allocations. +// +// It is unsafe to modify/copy request data after setting marshal data. +func (r *PutSingleRequestBody) SetMarshalData(data []byte) { + if r == nil { + return + } + + r.marshalData = data + + proto.NestedStructureSetMarshalData(putSingleReqObjectField, r.marshalData, r.object) +} + +func (r *PutSingleRequestBody) StableSize() int { + if r == nil { + return 0 + } + + var size int + size += proto.NestedStructureSize(putSingleReqObjectField, r.object) + arrSize, _ := proto.RepeatedUInt32Size(putSingleReqCopiesNumberField, r.copyNum) + size += arrSize + + return size +} + +func (r *PutSingleRequestBody) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.PutSingleRequest_Body)) +} + +func (r *PutSingleResponseBody) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + return buf +} + +func (r *PutSingleResponseBody) StableSize() int { + return 0 +} + +func (r *PutSingleResponseBody) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.PutSingleResponse_Body)) +} + +func (r *PatchRequestBodyPatch) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var offset int + offset += proto.NestedStructureMarshal(patchRequestBodyPatchRangeField, buf[offset:], r.GetRange()) + proto.BytesMarshal(patchRequestBodyPatchChunkField, buf[offset:], r.GetChunk()) + + return buf +} + +func (r *PatchRequestBodyPatch) StableSize() int { + if r == nil { + return 0 + } + + var size int + size += proto.NestedStructureSize(patchRequestBodyPatchRangeField, r.GetRange()) + size += proto.BytesSize(patchRequestBodyPatchChunkField, r.GetChunk()) + + return size +} + +func (r *PatchRequestBodyPatch) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.PatchRequest_Body_Patch)) +} + +func (r *PatchRequestBody) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var offset int + offset += proto.NestedStructureMarshal(patchRequestBodyAddrField, buf[offset:], r.address) + for i := range r.newAttributes { + offset += proto.NestedStructureMarshal(patchRequestBodyNewAttrsField, buf[offset:], &r.newAttributes[i]) + } + offset += proto.BoolMarshal(patchRequestBodyReplaceAttrField, buf[offset:], r.replaceAttributes) + proto.NestedStructureMarshal(patchRequestBodyPatchField, buf[offset:], r.patch) + + return buf +} + +func (r *PatchRequestBody) StableSize() int { + if r == nil { + return 0 + } + + var size int + size += proto.NestedStructureSize(patchRequestBodyAddrField, r.address) + for i := range r.newAttributes { + size += proto.NestedStructureSize(patchRequestBodyNewAttrsField, &r.newAttributes[i]) + } + size += proto.BoolSize(patchRequestBodyReplaceAttrField, r.replaceAttributes) + size += proto.NestedStructureSize(patchRequestBodyPatchField, r.patch) + + return size +} + +func (r *PatchRequestBody) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.PatchRequest_Body)) +} + +func (r *PatchResponseBody) StableSize() int { + if r == nil { + return 0 + } + + var size int + size += proto.NestedStructureSize(patchResponseBodyObjectIDField, r.ObjectID) + + return size +} + +func (r *PatchResponseBody) StableMarshal(buf []byte) []byte { + if r == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, r.StableSize()) + } + + var offset int + proto.NestedStructureMarshal(patchResponseBodyObjectIDField, buf[offset:], r.ObjectID) + + return buf +} + +func (r *PatchResponseBody) Unmarshal(data []byte) error { + return message.Unmarshal(r, data, new(object.PatchResponse_Body)) +} diff --git a/api/object/message_test.go b/api/object/message_test.go new file mode 100644 index 0000000..21568f8 --- /dev/null +++ b/api/object/message_test.go @@ -0,0 +1,65 @@ +package object_test + +import ( + "testing" + + objecttest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object/test" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + messagetest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message/test" +) + +func TestMessageConvert(t *testing.T) { + messagetest.TestRPCMessage(t, + func(empty bool) message.Message { return objecttest.GenerateShortHeader(empty) }, + func(empty bool) message.Message { return objecttest.GenerateAttribute(empty) }, + func(empty bool) message.Message { return objecttest.GenerateSplitHeader(empty) }, + func(empty bool) message.Message { return objecttest.GenerateHeaderWithSplitHeader(empty) }, + func(empty bool) message.Message { return objecttest.GenerateHeaderWithECHeader(empty) }, + func(empty bool) message.Message { return objecttest.GenerateECHeader(empty) }, + func(empty bool) message.Message { return objecttest.GenerateObject(empty) }, + func(empty bool) message.Message { return objecttest.GenerateSplitInfo(empty) }, + func(empty bool) message.Message { return objecttest.GenerateECInfo(empty) }, + func(empty bool) message.Message { return objecttest.GenerateGetRequestBody(empty) }, + func(empty bool) message.Message { return objecttest.GenerateGetRequest(empty) }, + func(empty bool) message.Message { return objecttest.GenerateGetObjectPartInit(empty) }, + func(empty bool) message.Message { return objecttest.GenerateGetObjectPartChunk(empty) }, + func(empty bool) message.Message { return objecttest.GenerateGetResponseBody(empty) }, + func(empty bool) message.Message { return objecttest.GenerateGetResponse(empty) }, + func(empty bool) message.Message { return objecttest.GeneratePutObjectPartInit(empty) }, + func(empty bool) message.Message { return objecttest.GeneratePutObjectPartChunk(empty) }, + func(empty bool) message.Message { return objecttest.GeneratePutRequestBody(empty) }, + func(empty bool) message.Message { return objecttest.GeneratePutRequest(empty) }, + func(empty bool) message.Message { return objecttest.GeneratePutResponseBody(empty) }, + func(empty bool) message.Message { return objecttest.GeneratePutResponse(empty) }, + func(empty bool) message.Message { return objecttest.GenerateDeleteRequestBody(empty) }, + func(empty bool) message.Message { return objecttest.GenerateDeleteRequest(empty) }, + func(empty bool) message.Message { return objecttest.GenerateDeleteResponseBody(empty) }, + func(empty bool) message.Message { return objecttest.GenerateDeleteResponse(empty) }, + func(empty bool) message.Message { return objecttest.GenerateHeadRequestBody(empty) }, + func(empty bool) message.Message { return objecttest.GenerateHeadRequest(empty) }, + func(empty bool) message.Message { return objecttest.GenerateHeadResponseBody(empty) }, + func(empty bool) message.Message { return objecttest.GenerateHeadResponse(empty) }, + func(empty bool) message.Message { return objecttest.GenerateSearchFilter(empty) }, + func(empty bool) message.Message { return objecttest.GenerateSearchRequestBody(empty) }, + func(empty bool) message.Message { return objecttest.GenerateSearchRequest(empty) }, + func(empty bool) message.Message { return objecttest.GenerateSearchResponseBody(empty) }, + func(empty bool) message.Message { return objecttest.GenerateSearchResponse(empty) }, + func(empty bool) message.Message { return objecttest.GenerateRange(empty) }, + func(empty bool) message.Message { return objecttest.GenerateGetRangeRequestBody(empty) }, + func(empty bool) message.Message { return objecttest.GenerateGetRangeRequest(empty) }, + func(empty bool) message.Message { return objecttest.GenerateGetRangeResponseBody(empty) }, + func(empty bool) message.Message { return objecttest.GenerateGetRangeResponse(empty) }, + func(empty bool) message.Message { return objecttest.GenerateGetRangeHashRequestBody(empty) }, + func(empty bool) message.Message { return objecttest.GenerateGetRangeHashRequest(empty) }, + func(empty bool) message.Message { return objecttest.GenerateGetRangeHashResponseBody(empty) }, + func(empty bool) message.Message { return objecttest.GenerateGetRangeHashResponse(empty) }, + func(empty bool) message.Message { return objecttest.GenerateLock(empty) }, + func(empty bool) message.Message { return objecttest.GeneratePutSingleRequest(empty) }, + func(empty bool) message.Message { return objecttest.GeneratePutSingleResponse(empty) }, + func(empty bool) message.Message { return objecttest.GeneratePatchRequestBodyPatch(empty) }, + func(empty bool) message.Message { return objecttest.GeneratePatchRequestBody(empty) }, + func(empty bool) message.Message { return objecttest.GeneratePatchRequest(empty) }, + func(empty bool) message.Message { return objecttest.GeneratePatchResponseBody(empty) }, + func(empty bool) message.Message { return objecttest.GeneratePatchResponse(empty) }, + ) +} diff --git a/api/object/status.go b/api/object/status.go new file mode 100644 index 0000000..32fda2b --- /dev/null +++ b/api/object/status.go @@ -0,0 +1,91 @@ +package object + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status" + statusgrpc "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status/grpc" +) + +// LocalizeFailStatus checks if passed global status.Code is related to object failure and: +// +// then localizes the code and returns true, +// else leaves the code unchanged and returns false. +// +// Arg must not be nil. +func LocalizeFailStatus(c *status.Code) bool { + return status.LocalizeIfInSection(c, uint32(statusgrpc.Section_SECTION_OBJECT)) +} + +// GlobalizeFail globalizes local code of object failure. +// +// Arg must not be nil. +func GlobalizeFail(c *status.Code) { + c.GlobalizeSection(uint32(statusgrpc.Section_SECTION_OBJECT)) +} + +const ( + // StatusAccessDenied is a local status.Code value for + // ACCESS_DENIED object failure. + StatusAccessDenied status.Code = iota + // StatusNotFound is a local status.Code value for + // OBJECT_NOT_FOUND object failure. + StatusNotFound + // StatusLocked is a local status.Code value for + // LOCKED object failure. + StatusLocked + // StatusLockNonRegularObject is a local status.Code value for + // LOCK_NON_REGULAR_OBJECT object failure. + StatusLockNonRegularObject + // StatusAlreadyRemoved is a local status.Code value for + // OBJECT_ALREADY_REMOVED object failure. + StatusAlreadyRemoved + // StatusOutOfRange is a local status.Code value for + // OUT_OF_RANGE object failure. + StatusOutOfRange +) + +const ( + // detailAccessDeniedDesc is a StatusAccessDenied detail ID for + // human-readable description. + detailAccessDeniedDesc = iota +) + +// WriteAccessDeniedDesc writes human-readable description of StatusAccessDenied +// into status.Status as a detail. The status must not be nil. +// +// Existing details are expected to be ID-unique, otherwise undefined behavior. +func WriteAccessDeniedDesc(st *status.Status, desc string) { + var found bool + + st.IterateDetails(func(d *status.Detail) bool { + if d.ID() == detailAccessDeniedDesc { + found = true + d.SetValue([]byte(desc)) + } + + return found + }) + + if !found { + var d status.Detail + + d.SetID(detailAccessDeniedDesc) + d.SetValue([]byte(desc)) + + st.AppendDetails(d) + } +} + +// ReadAccessDeniedDesc looks up for status detail with human-readable description +// of StatusAccessDenied. Returns empty string if detail is missing. +func ReadAccessDeniedDesc(st status.Status) (desc string) { + st.IterateDetails(func(d *status.Detail) bool { + if d.ID() == detailAccessDeniedDesc { + desc = string(d.Value()) + return true + } + + return false + }) + + return +} diff --git a/api/object/status_test.go b/api/object/status_test.go new file mode 100644 index 0000000..465f5c8 --- /dev/null +++ b/api/object/status_test.go @@ -0,0 +1,35 @@ +package object_test + +import ( + "testing" + + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status" + statustest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status/test" + "github.com/stretchr/testify/require" +) + +func TestStatusCodes(t *testing.T) { + statustest.TestCodes(t, object.LocalizeFailStatus, object.GlobalizeFail, + object.StatusAccessDenied, 2048, + object.StatusNotFound, 2049, + object.StatusLocked, 2050, + object.StatusLockNonRegularObject, 2051, + object.StatusAlreadyRemoved, 2052, + object.StatusOutOfRange, 2053, + ) +} + +func TestAccessDeniedDesc(t *testing.T) { + var st status.Status + + require.Empty(t, object.ReadAccessDeniedDesc(st)) + + const desc = "some description" + + object.WriteAccessDeniedDesc(&st, desc) + require.Equal(t, desc, object.ReadAccessDeniedDesc(st)) + + object.WriteAccessDeniedDesc(&st, desc+"1") + require.Equal(t, desc+"1", object.ReadAccessDeniedDesc(st)) +} diff --git a/api/object/string.go b/api/object/string.go new file mode 100644 index 0000000..9910df7 --- /dev/null +++ b/api/object/string.go @@ -0,0 +1,55 @@ +package object + +import ( + object "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object/grpc" +) + +// String returns string representation of Type. +func (t Type) String() string { + return TypeToGRPCField(t).String() +} + +// FromString parses Type from a string representation. +// It is a reverse action to String(). +// +// Returns true if s was parsed successfully. +func (t *Type) FromString(s string) bool { + var g object.ObjectType + + ok := g.FromString(s) + + if ok { + *t = TypeFromGRPCField(g) + } + + return ok +} + +// TypeFromString converts string to Type. +// +// Deprecated: use FromString method. +func TypeFromString(s string) (t Type) { + t.FromString(s) + return +} + +// String returns string representation of MatchType. +func (t MatchType) String() string { + return MatchTypeToGRPCField(t).String() +} + +// FromString parses MatchType from a string representation. +// It is a reverse action to String(). +// +// Returns true if s was parsed successfully. +func (t *MatchType) FromString(s string) bool { + var g object.MatchType + + ok := g.FromString(s) + + if ok { + *t = MatchTypeFromGRPCField(g) + } + + return ok +} diff --git a/api/object/test/generate.go b/api/object/test/generate.go new file mode 100644 index 0000000..37345f9 --- /dev/null +++ b/api/object/test/generate.go @@ -0,0 +1,766 @@ +package objecttest + +import ( + crand "crypto/rand" + "math/rand" + "time" + + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + refstest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs/test" + sessiontest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session/test" +) + +func GenerateShortHeader(empty bool) *object.ShortHeader { + m := new(object.ShortHeader) + + if !empty { + m.SetObjectType(13) + m.SetCreationEpoch(100) + m.SetPayloadLength(12321) + m.SetOwnerID(refstest.GenerateOwnerID(false)) + } + + m.SetVersion(refstest.GenerateVersion(empty)) + m.SetHomomorphicHash(refstest.GenerateChecksum(empty)) + m.SetPayloadHash(refstest.GenerateChecksum(empty)) + + return m +} + +func GenerateAttribute(empty bool) *object.Attribute { + m := new(object.Attribute) + + if !empty { + m.SetKey("object key") + m.SetValue("object value") + } + + return m +} + +func GenerateAttributes(empty bool) []object.Attribute { + var res []object.Attribute + + if !empty { + res = append(res, + *GenerateAttribute(false), + *GenerateAttribute(false), + ) + } + + return res +} + +func GenerateSplitHeader(empty bool) *object.SplitHeader { + return generateSplitHeader(empty, true) +} + +func generateSplitHeader(empty, withPar bool) *object.SplitHeader { + m := new(object.SplitHeader) + + if !empty { + id := make([]byte, 16) + _, _ = crand.Read(id) + + m.SetSplitID(id) + m.SetParent(refstest.GenerateObjectID(false)) + m.SetPrevious(refstest.GenerateObjectID(false)) + m.SetChildren(refstest.GenerateObjectIDs(false)) + } + + m.SetParentSignature(refstest.GenerateSignature(empty)) + + if withPar { + m.SetParentHeader(GenerateHeaderWithSplitHeader(empty)) + } + + return m +} + +func GenerateHeaderWithSplitHeader(empty bool) *object.Header { + m := generateHeader(empty) + m.SetSplit(generateSplitHeader(empty, false)) + return m +} + +func GenerateHeaderWithECHeader(empty bool) *object.Header { + m := generateHeader(empty) + m.SetEC(GenerateECHeader(empty)) + return m +} + +func GenerateECHeader(empty bool) *object.ECHeader { + ech := new(object.ECHeader) + + if !empty { + ech.Parent = refstest.GenerateObjectID(empty) + + ech.ParentSplitID = make([]byte, 16) + _, _ = crand.Read(ech.ParentSplitID) + + ech.ParentSplitParentID = refstest.GenerateObjectID(empty) + ech.ParentAttributes = GenerateAttributes(empty) + ech.Index = 0 + ech.Total = 2 + ech.Header = []byte("chunk of ec-encoded parent header") + ech.HeaderLength = uint32(2 * len(ech.Header)) + } + + return ech +} + +func generateHeader(empty bool) *object.Header { + m := new(object.Header) + + if !empty { + m.SetPayloadLength(777) + m.SetCreationEpoch(432) + m.SetObjectType(111) + m.SetOwnerID(refstest.GenerateOwnerID(false)) + m.SetContainerID(refstest.GenerateContainerID(false)) + m.SetAttributes(GenerateAttributes(false)) + } + + m.SetVersion(refstest.GenerateVersion(empty)) + m.SetPayloadHash(refstest.GenerateChecksum(empty)) + m.SetHomomorphicHash(refstest.GenerateChecksum(empty)) + m.SetSessionToken(sessiontest.GenerateSessionToken(empty)) + + return m +} + +func GenerateHeaderWithSignature(empty bool) *object.HeaderWithSignature { + m := new(object.HeaderWithSignature) + + m.SetSignature(refstest.GenerateSignature(empty)) + m.SetHeader(GenerateHeaderWithSplitHeader(empty)) + + return m +} + +func GenerateObject(empty bool) *object.Object { + m := new(object.Object) + + if !empty { + m.SetPayload([]byte{7, 8, 9}) + m.SetObjectID(refstest.GenerateObjectID(false)) + } + + m.SetSignature(refstest.GenerateSignature(empty)) + m.SetHeader(GenerateHeaderWithSplitHeader(empty)) + + return m +} + +func GenerateSplitInfo(empty bool) *object.SplitInfo { + m := new(object.SplitInfo) + + if !empty { + id := make([]byte, 16) + _, _ = crand.Read(id) + + m.SetSplitID(id) + m.SetLastPart(refstest.GenerateObjectID(false)) + m.SetLink(refstest.GenerateObjectID(false)) + } + + return m +} + +func GenerateECInfo(empty bool) *object.ECInfo { + m := new(object.ECInfo) + + if !empty { + m.Chunks = make([]object.ECChunk, 2) + for i := range m.Chunks { + m.Chunks[i] = *GenerateECChunk(false) + } + } + + return m +} + +func GenerateECChunk(empty bool) *object.ECChunk { + m := new(object.ECChunk) + + if !empty { + m.ID = *refstest.GenerateObjectID(false) + m.Index = 4 + m.Total = 7 + } + + return m +} + +func GenerateGetRequestBody(empty bool) *object.GetRequestBody { + m := new(object.GetRequestBody) + + if !empty { + m.SetRaw(true) + m.SetAddress(refstest.GenerateAddress(false)) + } + + return m +} + +func GenerateGetRequest(empty bool) *object.GetRequest { + m := new(object.GetRequest) + + if !empty { + m.SetBody(GenerateGetRequestBody(false)) + } + + m.SetMetaHeader(sessiontest.GenerateRequestMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateRequestVerificationHeader(empty)) + + return m +} + +func GenerateGetObjectPartInit(empty bool) *object.GetObjectPartInit { + m := new(object.GetObjectPartInit) + + if !empty { + m.SetObjectID(refstest.GenerateObjectID(false)) + } + + m.SetSignature(refstest.GenerateSignature(empty)) + m.SetHeader(GenerateHeaderWithSplitHeader(empty)) + + return m +} + +func GenerateGetObjectPartChunk(empty bool) *object.GetObjectPartChunk { + m := new(object.GetObjectPartChunk) + + if !empty { + m.SetChunk([]byte("get chunk")) + } + + return m +} + +func GenerateGetResponseBody(empty bool) *object.GetResponseBody { + m := new(object.GetResponseBody) + + if !empty { + switch randomInt(3) { + case 0: + m.SetObjectPart(GenerateGetObjectPartInit(false)) + case 1: + m.SetObjectPart(GenerateGetObjectPartChunk(false)) + case 2: + m.SetObjectPart(GenerateSplitInfo(false)) + } + } + + return m +} + +func GenerateGetResponse(empty bool) *object.GetResponse { + m := new(object.GetResponse) + + if !empty { + m.SetBody(GenerateGetResponseBody(false)) + } + + m.SetMetaHeader(sessiontest.GenerateResponseMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateResponseVerificationHeader(empty)) + + return m +} + +func GeneratePutObjectPartInit(empty bool) *object.PutObjectPartInit { + m := new(object.PutObjectPartInit) + + if !empty { + m.SetCopiesNumber([]uint32{234}) + m.SetObjectID(refstest.GenerateObjectID(false)) + } + + m.SetSignature(refstest.GenerateSignature(empty)) + m.SetHeader(GenerateHeaderWithSplitHeader(empty)) + + return m +} + +func GeneratePutObjectPartChunk(empty bool) *object.PutObjectPartChunk { + m := new(object.PutObjectPartChunk) + + if !empty { + m.SetChunk([]byte("put chunk")) + } + + return m +} + +func GeneratePutRequestBody(empty bool) *object.PutRequestBody { + m := new(object.PutRequestBody) + + if !empty { + switch randomInt(2) { + case 0: + m.SetObjectPart(GeneratePutObjectPartInit(false)) + case 1: + m.SetObjectPart(GeneratePutObjectPartChunk(false)) + } + } + + return m +} + +func GeneratePutRequest(empty bool) *object.PutRequest { + m := new(object.PutRequest) + + if !empty { + m.SetBody(GeneratePutRequestBody(false)) + } + + m.SetMetaHeader(sessiontest.GenerateRequestMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateRequestVerificationHeader(empty)) + + return m +} + +func GeneratePutResponseBody(empty bool) *object.PutResponseBody { + m := new(object.PutResponseBody) + + if !empty { + m.SetObjectID(refstest.GenerateObjectID(false)) + } + + return m +} + +func GeneratePutResponse(empty bool) *object.PutResponse { + m := new(object.PutResponse) + + if !empty { + m.SetBody(GeneratePutResponseBody(false)) + } + + m.SetMetaHeader(sessiontest.GenerateResponseMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateResponseVerificationHeader(empty)) + + return m +} + +func GenerateDeleteRequestBody(empty bool) *object.DeleteRequestBody { + m := new(object.DeleteRequestBody) + + if !empty { + m.SetAddress(refstest.GenerateAddress(false)) + } + + return m +} + +func GenerateDeleteRequest(empty bool) *object.DeleteRequest { + m := new(object.DeleteRequest) + + if !empty { + m.SetBody(GenerateDeleteRequestBody(false)) + } + + m.SetMetaHeader(sessiontest.GenerateRequestMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateRequestVerificationHeader(empty)) + + return m +} + +func GenerateDeleteResponseBody(empty bool) *object.DeleteResponseBody { + m := new(object.DeleteResponseBody) + + if !empty { + m.SetTombstone(refstest.GenerateAddress(false)) + } + + return m +} + +func GenerateDeleteResponse(empty bool) *object.DeleteResponse { + m := new(object.DeleteResponse) + + if !empty { + m.SetBody(GenerateDeleteResponseBody(false)) + } + + m.SetMetaHeader(sessiontest.GenerateResponseMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateResponseVerificationHeader(empty)) + + return m +} + +func GenerateHeadRequestBody(empty bool) *object.HeadRequestBody { + m := new(object.HeadRequestBody) + + if !empty { + m.SetRaw(true) + m.SetMainOnly(true) + m.SetAddress(refstest.GenerateAddress(false)) + } + + return m +} + +func GenerateHeadRequest(empty bool) *object.HeadRequest { + m := new(object.HeadRequest) + + if !empty { + m.SetBody(GenerateHeadRequestBody(false)) + } + + m.SetMetaHeader(sessiontest.GenerateRequestMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateRequestVerificationHeader(empty)) + + return m +} + +func GenerateHeadResponseBody(empty bool) *object.HeadResponseBody { + m := new(object.HeadResponseBody) + + if !empty { + switch randomInt(3) { + case 0: + m.SetHeaderPart(GenerateHeaderWithSignature(false)) + case 1: + m.SetHeaderPart(GenerateShortHeader(false)) + case 2: + m.SetHeaderPart(GenerateSplitInfo(false)) + } + } + + return m +} + +func GenerateHeadResponse(empty bool) *object.HeadResponse { + m := new(object.HeadResponse) + + if !empty { + m.SetBody(GenerateHeadResponseBody(false)) + } + + m.SetMetaHeader(sessiontest.GenerateResponseMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateResponseVerificationHeader(empty)) + + return m +} + +func GenerateSearchFilter(empty bool) *object.SearchFilter { + m := new(object.SearchFilter) + + if !empty { + m.SetKey("search filter key") + m.SetValue("search filter val") + m.SetMatchType(987) + } + + return m +} + +func GenerateSearchFilters(empty bool) []object.SearchFilter { + var res []object.SearchFilter + + if !empty { + res = append(res, + *GenerateSearchFilter(false), + *GenerateSearchFilter(false), + ) + } + + return res +} + +func GenerateSearchRequestBody(empty bool) *object.SearchRequestBody { + m := new(object.SearchRequestBody) + + if !empty { + m.SetVersion(555) + m.SetContainerID(refstest.GenerateContainerID(false)) + m.SetFilters(GenerateSearchFilters(false)) + } + + return m +} + +func GenerateSearchRequest(empty bool) *object.SearchRequest { + m := new(object.SearchRequest) + + if !empty { + m.SetBody(GenerateSearchRequestBody(false)) + } + + m.SetMetaHeader(sessiontest.GenerateRequestMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateRequestVerificationHeader(empty)) + + return m +} + +func GenerateSearchResponseBody(empty bool) *object.SearchResponseBody { + m := new(object.SearchResponseBody) + + if !empty { + m.SetIDList(refstest.GenerateObjectIDs(false)) + } + + return m +} + +func GenerateSearchResponse(empty bool) *object.SearchResponse { + m := new(object.SearchResponse) + + if !empty { + m.SetBody(GenerateSearchResponseBody(false)) + } + + m.SetMetaHeader(sessiontest.GenerateResponseMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateResponseVerificationHeader(empty)) + + return m +} + +func GenerateRange(empty bool) *object.Range { + m := new(object.Range) + + if !empty { + m.SetLength(11) + m.SetOffset(22) + } + + return m +} + +func GenerateRanges(empty bool) []object.Range { + var res []object.Range + + if !empty { + res = append(res, + *GenerateRange(false), + *GenerateRange(false), + ) + } + + return res +} + +func GenerateGetRangeRequestBody(empty bool) *object.GetRangeRequestBody { + m := new(object.GetRangeRequestBody) + + if !empty { + m.SetRaw(true) + m.SetAddress(refstest.GenerateAddress(empty)) + m.SetRange(GenerateRange(empty)) + } + + return m +} + +func GenerateGetRangeRequest(empty bool) *object.GetRangeRequest { + m := new(object.GetRangeRequest) + + if !empty { + m.SetBody(GenerateGetRangeRequestBody(false)) + } + + m.SetMetaHeader(sessiontest.GenerateRequestMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateRequestVerificationHeader(empty)) + + return m +} + +func GenerateGetRangePartChunk(empty bool) *object.GetRangePartChunk { + m := new(object.GetRangePartChunk) + + if !empty { + m.SetChunk([]byte("get range chunk")) + } + + return m +} + +func GenerateGetRangeResponseBody(empty bool) *object.GetRangeResponseBody { + m := new(object.GetRangeResponseBody) + + if !empty { + switch randomInt(2) { + case 0: + m.SetRangePart(GenerateGetRangePartChunk(false)) + case 1: + m.SetRangePart(GenerateSplitInfo(false)) + } + } + + return m +} + +func GenerateGetRangeResponse(empty bool) *object.GetRangeResponse { + m := new(object.GetRangeResponse) + + if !empty { + m.SetBody(GenerateGetRangeResponseBody(false)) + } + + m.SetMetaHeader(sessiontest.GenerateResponseMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateResponseVerificationHeader(empty)) + + return m +} + +func GenerateGetRangeHashRequestBody(empty bool) *object.GetRangeHashRequestBody { + m := new(object.GetRangeHashRequestBody) + + if !empty { + m.SetSalt([]byte("range hash salt")) + m.SetType(455) + m.SetAddress(refstest.GenerateAddress(false)) + m.SetRanges(GenerateRanges(false)) + } + + return m +} + +func GenerateGetRangeHashRequest(empty bool) *object.GetRangeHashRequest { + m := new(object.GetRangeHashRequest) + + if !empty { + m.SetBody(GenerateGetRangeHashRequestBody(false)) + } + + m.SetMetaHeader(sessiontest.GenerateRequestMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateRequestVerificationHeader(empty)) + + return m +} + +func GenerateGetRangeHashResponseBody(empty bool) *object.GetRangeHashResponseBody { + m := new(object.GetRangeHashResponseBody) + + if !empty { + m.SetType(678) + m.SetHashList([][]byte{ + refstest.GenerateChecksum(false).GetSum(), + refstest.GenerateChecksum(false).GetSum(), + }) + } + + return m +} + +func GenerateGetRangeHashResponse(empty bool) *object.GetRangeHashResponse { + m := new(object.GetRangeHashResponse) + + if !empty { + m.SetBody(GenerateGetRangeHashResponseBody(false)) + } + + m.SetMetaHeader(sessiontest.GenerateResponseMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateResponseVerificationHeader(empty)) + + return m +} + +func GenerateLock(empty bool) *object.Lock { + m := new(object.Lock) + + if !empty { + m.SetMembers([]refs.ObjectID{ + *refstest.GenerateObjectID(false), + *refstest.GenerateObjectID(false), + }) + } + + return m +} + +func GeneratePutSingleRequest(empty bool) *object.PutSingleRequest { + m := new(object.PutSingleRequest) + + if !empty { + m.SetBody(GeneratePutSingleRequestBody(false)) + } + + m.SetMetaHeader(sessiontest.GenerateRequestMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateRequestVerificationHeader(empty)) + + return m +} + +func GeneratePutSingleRequestBody(empty bool) *object.PutSingleRequestBody { + b := new(object.PutSingleRequestBody) + if !empty { + b.SetObject(GenerateObject(empty)) + b.SetCopiesNumber([]uint32{12345}) + } + return b +} + +func GeneratePutSingleResponse(empty bool) *object.PutSingleResponse { + m := new(object.PutSingleResponse) + if !empty { + m.SetBody(new(object.PutSingleResponseBody)) + } + m.SetMetaHeader(sessiontest.GenerateResponseMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateResponseVerificationHeader(empty)) + return m +} + +func GeneratePatchRequestBodyPatch(empty bool) *object.PatchRequestBodyPatch { + m := new(object.PatchRequestBodyPatch) + + if !empty { + m.Range = GenerateRange(false) + m.Chunk = []byte("GeneratePatchRequestBodyPatch") + } + + return m +} + +func GeneratePatchRequestBody(empty bool) *object.PatchRequestBody { + m := new(object.PatchRequestBody) + + if !empty { + m.SetAddress(refstest.GenerateAddress(empty)) + m.SetNewAttributes(GenerateAttributes(empty)) + m.SetReplaceAttributes(false) + m.SetPatch(GeneratePatchRequestBodyPatch(empty)) + } + + return m +} + +func GeneratePatchRequest(empty bool) *object.PatchRequest { + m := new(object.PatchRequest) + + if !empty { + m.SetBody(GeneratePatchRequestBody(empty)) + } + + m.SetMetaHeader(sessiontest.GenerateRequestMetaHeader(empty)) + m.SetVerificationHeader(sessiontest.GenerateRequestVerificationHeader(empty)) + + return m +} + +func GeneratePatchResponseBody(empty bool) *object.PatchResponseBody { + m := new(object.PatchResponseBody) + + if !empty { + m.ObjectID = refstest.GenerateObjectID(empty) + } + + return m +} + +func GeneratePatchResponse(empty bool) *object.PatchResponse { + m := new(object.PatchResponse) + + if !empty { + m.Body = GeneratePatchResponseBody(empty) + } + + return m +} + +func randomInt(n int) int { + return rand.New(rand.NewSource(time.Now().UnixNano())).Intn(n) +} diff --git a/api/object/types.go b/api/object/types.go new file mode 100644 index 0000000..537fb02 --- /dev/null +++ b/api/object/types.go @@ -0,0 +1,1650 @@ +package object + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" +) + +type Type uint32 + +type MatchType uint32 + +type ShortHeader struct { + version *refs.Version + + creatEpoch uint64 + + ownerID *refs.OwnerID + + typ Type + + payloadLen uint64 + + payloadHash, homoHash *refs.Checksum +} + +type Attribute struct { + key, val string +} + +type SplitHeader struct { + par, prev *refs.ObjectID + + parSig *refs.Signature + + parHdr *Header + + children []refs.ObjectID + + splitID []byte +} + +type ECHeader struct { + Parent *refs.ObjectID + ParentSplitID []byte + ParentSplitParentID *refs.ObjectID + ParentAttributes []Attribute + Index uint32 + Total uint32 + Header []byte + HeaderLength uint32 +} + +type Header struct { + version *refs.Version + + cid *refs.ContainerID + + ownerID *refs.OwnerID + + creatEpoch uint64 + + payloadLen uint64 + + payloadHash, homoHash *refs.Checksum + + typ Type + + sessionToken *session.Token + + attr []Attribute + + split *SplitHeader + + ec *ECHeader +} + +type HeaderWithSignature struct { + header *Header + + signature *refs.Signature +} + +type Object struct { + objectID *refs.ObjectID + + idSig *refs.Signature + + header *Header + + payload []byte + + // marshalData holds marshaled data, must not be marshaled by StableMarshal + marshalData []byte +} + +type SplitInfo struct { + splitID []byte + + lastPart *refs.ObjectID + + link *refs.ObjectID +} + +type ECChunk struct { + ID refs.ObjectID + Index uint32 + Total uint32 +} + +type ECInfo struct { + Chunks []ECChunk +} + +type GetRequestBody struct { + addr *refs.Address + + raw bool +} + +type GetObjectPart interface { + getObjectPart() +} + +type GetObjectPartInit struct { + id *refs.ObjectID + + sig *refs.Signature + + hdr *Header +} + +type GetObjectPartChunk struct { + chunk []byte +} + +type GetRequest struct { + body *GetRequestBody + + session.RequestHeaders +} + +type GetResponseBody struct { + objPart GetObjectPart +} + +type PutObjectPart interface { + putObjectPart() +} + +type PutObjectPartInit struct { + id *refs.ObjectID + + sig *refs.Signature + + hdr *Header + + copyNum []uint32 +} + +type PutObjectPartChunk struct { + chunk []byte +} + +type GetResponse struct { + body *GetResponseBody + + session.ResponseHeaders +} + +type PutRequestBody struct { + objPart PutObjectPart +} + +type PutRequest struct { + body *PutRequestBody + + session.RequestHeaders +} + +type PutResponseBody struct { + id *refs.ObjectID +} + +type PutResponse struct { + body *PutResponseBody + + session.ResponseHeaders +} + +type DeleteRequestBody struct { + addr *refs.Address +} + +type DeleteRequest struct { + body *DeleteRequestBody + + session.RequestHeaders +} + +type DeleteResponseBody struct { + tombstone *refs.Address +} + +type DeleteResponse struct { + body *DeleteResponseBody + + session.ResponseHeaders +} + +type HeadRequestBody struct { + addr *refs.Address + + mainOnly, raw bool +} + +type GetHeaderPart interface { + getHeaderPart() +} + +type HeadRequest struct { + body *HeadRequestBody + + session.RequestHeaders +} + +type HeadResponseBody struct { + hdrPart GetHeaderPart +} + +type HeadResponse struct { + body *HeadResponseBody + + session.ResponseHeaders +} + +type SearchFilter struct { + matchType MatchType + + key, val string +} + +type SearchRequestBody struct { + cid *refs.ContainerID + + version uint32 + + filters []SearchFilter +} + +type SearchRequest struct { + body *SearchRequestBody + + session.RequestHeaders +} + +type SearchResponseBody struct { + idList []refs.ObjectID +} + +type SearchResponse struct { + body *SearchResponseBody + + session.ResponseHeaders +} + +type Range struct { + off, len uint64 +} + +type GetRangeRequestBody struct { + addr *refs.Address + + rng *Range + + raw bool +} + +type GetRangeRequest struct { + body *GetRangeRequestBody + + session.RequestHeaders +} + +type GetRangePart interface { + getRangePart() +} + +type GetRangePartChunk struct { + chunk []byte +} + +type GetRangeResponseBody struct { + rngPart GetRangePart +} + +type GetRangeResponse struct { + body *GetRangeResponseBody + + session.ResponseHeaders +} + +type GetRangeHashRequestBody struct { + addr *refs.Address + + rngs []Range + + salt []byte + + typ refs.ChecksumType +} + +type GetRangeHashRequest struct { + body *GetRangeHashRequestBody + + session.RequestHeaders +} + +type GetRangeHashResponseBody struct { + typ refs.ChecksumType + + hashList [][]byte +} + +type GetRangeHashResponse struct { + body *GetRangeHashResponseBody + + session.ResponseHeaders +} + +type PutSingleRequestBody struct { + object *Object + copyNum []uint32 + + // marshalData holds marshaled data, must not be marshaled by StableMarshal + marshalData []byte +} + +type PutSingleRequest struct { + body *PutSingleRequestBody + + session.RequestHeaders +} + +type PutSingleResponseBody struct{} + +type PutSingleResponse struct { + body *PutSingleResponseBody + + session.ResponseHeaders +} + +type PatchRequestBodyPatch struct { + Range *Range + + Chunk []byte +} + +type PatchRequestBody struct { + address *refs.Address + + newAttributes []Attribute + + replaceAttributes bool + + patch *PatchRequestBodyPatch +} + +type PatchRequest struct { + body *PatchRequestBody + + session.RequestHeaders +} + +type PatchResponseBody struct { + ObjectID *refs.ObjectID +} + +type PatchResponse struct { + Body *PatchResponseBody + + session.ResponseHeaders +} + +const ( + TypeRegular Type = iota + TypeTombstone + _ + TypeLock +) + +const ( + MatchUnknown MatchType = iota + MatchStringEqual + MatchStringNotEqual + MatchNotPresent + MatchCommonPrefix +) + +func (h *ShortHeader) GetVersion() *refs.Version { + if h != nil { + return h.version + } + + return nil +} + +func (h *ShortHeader) SetVersion(v *refs.Version) { + h.version = v +} + +func (h *ShortHeader) GetCreationEpoch() uint64 { + if h != nil { + return h.creatEpoch + } + + return 0 +} + +func (h *ShortHeader) SetCreationEpoch(v uint64) { + h.creatEpoch = v +} + +func (h *ShortHeader) GetOwnerID() *refs.OwnerID { + if h != nil { + return h.ownerID + } + + return nil +} + +func (h *ShortHeader) SetOwnerID(v *refs.OwnerID) { + h.ownerID = v +} + +func (h *ShortHeader) GetObjectType() Type { + if h != nil { + return h.typ + } + + return TypeRegular +} + +func (h *ShortHeader) SetObjectType(v Type) { + h.typ = v +} + +func (h *ShortHeader) GetPayloadLength() uint64 { + if h != nil { + return h.payloadLen + } + + return 0 +} + +func (h *ShortHeader) SetPayloadLength(v uint64) { + h.payloadLen = v +} + +func (h *ShortHeader) GetPayloadHash() *refs.Checksum { + if h != nil { + return h.payloadHash + } + + return nil +} + +func (h *ShortHeader) SetPayloadHash(v *refs.Checksum) { + h.payloadHash = v +} + +func (h *ShortHeader) GetHomomorphicHash() *refs.Checksum { + if h != nil { + return h.homoHash + } + + return nil +} + +func (h *ShortHeader) SetHomomorphicHash(v *refs.Checksum) { + h.homoHash = v +} + +func (h *ShortHeader) getHeaderPart() {} + +func (a *Attribute) GetKey() string { + if a != nil { + return a.key + } + + return "" +} + +func (a *Attribute) SetKey(v string) { + a.key = v +} + +func (a *Attribute) GetValue() string { + if a != nil { + return a.val + } + + return "" +} + +func (a *Attribute) SetValue(v string) { + a.val = v +} + +func (h *SplitHeader) GetParent() *refs.ObjectID { + if h != nil { + return h.par + } + + return nil +} + +func (h *SplitHeader) SetParent(v *refs.ObjectID) { + h.par = v +} + +func (h *SplitHeader) GetPrevious() *refs.ObjectID { + if h != nil { + return h.prev + } + + return nil +} + +func (h *SplitHeader) SetPrevious(v *refs.ObjectID) { + h.prev = v +} + +func (h *SplitHeader) GetParentSignature() *refs.Signature { + if h != nil { + return h.parSig + } + + return nil +} + +func (h *SplitHeader) SetParentSignature(v *refs.Signature) { + h.parSig = v +} + +func (h *SplitHeader) GetParentHeader() *Header { + if h != nil { + return h.parHdr + } + + return nil +} + +func (h *SplitHeader) SetParentHeader(v *Header) { + h.parHdr = v +} + +func (h *SplitHeader) GetChildren() []refs.ObjectID { + if h != nil { + return h.children + } + + return nil +} + +func (h *SplitHeader) SetChildren(v []refs.ObjectID) { + h.children = v +} + +func (h *SplitHeader) GetSplitID() []byte { + if h != nil { + return h.splitID + } + + return nil +} + +func (h *SplitHeader) SetSplitID(v []byte) { + h.splitID = v +} + +func (h *Header) GetVersion() *refs.Version { + if h != nil { + return h.version + } + + return nil +} + +func (h *Header) SetVersion(v *refs.Version) { + h.version = v +} + +func (h *Header) GetContainerID() *refs.ContainerID { + if h != nil { + return h.cid + } + + return nil +} + +func (h *Header) SetContainerID(v *refs.ContainerID) { + h.cid = v +} + +func (h *Header) GetOwnerID() *refs.OwnerID { + if h != nil { + return h.ownerID + } + + return nil +} + +func (h *Header) SetOwnerID(v *refs.OwnerID) { + h.ownerID = v +} + +func (h *Header) GetCreationEpoch() uint64 { + if h != nil { + return h.creatEpoch + } + + return 0 +} + +func (h *Header) SetCreationEpoch(v uint64) { + h.creatEpoch = v +} + +func (h *Header) GetPayloadLength() uint64 { + if h != nil { + return h.payloadLen + } + + return 0 +} + +func (h *Header) SetPayloadLength(v uint64) { + h.payloadLen = v +} + +func (h *Header) GetPayloadHash() *refs.Checksum { + if h != nil { + return h.payloadHash + } + + return nil +} + +func (h *Header) SetPayloadHash(v *refs.Checksum) { + h.payloadHash = v +} + +func (h *Header) GetObjectType() Type { + if h != nil { + return h.typ + } + + return TypeRegular +} + +func (h *Header) SetObjectType(v Type) { + h.typ = v +} + +func (h *Header) GetHomomorphicHash() *refs.Checksum { + if h != nil { + return h.homoHash + } + + return nil +} + +func (h *Header) SetHomomorphicHash(v *refs.Checksum) { + h.homoHash = v +} + +func (h *Header) GetSessionToken() *session.Token { + if h != nil { + return h.sessionToken + } + + return nil +} + +func (h *Header) SetSessionToken(v *session.Token) { + h.sessionToken = v +} + +func (h *Header) GetAttributes() []Attribute { + if h != nil { + return h.attr + } + + return nil +} + +func (h *Header) SetAttributes(v []Attribute) { + h.attr = v +} + +func (h *Header) GetSplit() *SplitHeader { + if h != nil { + return h.split + } + + return nil +} + +func (h *Header) SetSplit(v *SplitHeader) { + h.split = v +} + +func (h *Header) GetEC() *ECHeader { + if h != nil { + return h.ec + } + return nil +} + +func (h *Header) SetEC(v *ECHeader) { + h.ec = v +} + +func (h *HeaderWithSignature) GetHeader() *Header { + if h != nil { + return h.header + } + + return nil +} + +func (h *HeaderWithSignature) SetHeader(v *Header) { + h.header = v +} + +func (h *HeaderWithSignature) GetSignature() *refs.Signature { + if h != nil { + return h.signature + } + + return nil +} + +func (h *HeaderWithSignature) SetSignature(v *refs.Signature) { + h.signature = v +} + +func (h *HeaderWithSignature) getHeaderPart() {} + +func (o *Object) GetObjectID() *refs.ObjectID { + if o != nil { + return o.objectID + } + + return nil +} + +func (o *Object) SetObjectID(v *refs.ObjectID) { + o.objectID = v +} + +func (o *Object) GetSignature() *refs.Signature { + if o != nil { + return o.idSig + } + + return nil +} + +func (o *Object) SetSignature(v *refs.Signature) { + o.idSig = v +} + +func (o *Object) GetHeader() *Header { + if o != nil { + return o.header + } + + return nil +} + +func (o *Object) SetHeader(v *Header) { + o.header = v +} + +func (o *Object) GetPayload() []byte { + if o != nil { + return o.payload + } + + return nil +} + +func (o *Object) SetPayload(v []byte) { + o.payload = v +} + +func (s *SplitInfo) GetSplitID() []byte { + if s != nil { + return s.splitID + } + + return nil +} + +func (s *SplitInfo) SetSplitID(v []byte) { + s.splitID = v +} + +func (s *SplitInfo) GetLastPart() *refs.ObjectID { + if s != nil { + return s.lastPart + } + + return nil +} + +func (s *SplitInfo) SetLastPart(v *refs.ObjectID) { + s.lastPart = v +} + +func (s *SplitInfo) GetLink() *refs.ObjectID { + if s != nil { + return s.link + } + + return nil +} + +func (s *SplitInfo) SetLink(v *refs.ObjectID) { + s.link = v +} + +func (s *SplitInfo) getObjectPart() {} + +func (s *SplitInfo) getHeaderPart() {} + +func (s *SplitInfo) getRangePart() {} + +func (r *GetRequestBody) GetAddress() *refs.Address { + if r != nil { + return r.addr + } + + return nil +} + +func (r *GetRequestBody) SetAddress(v *refs.Address) { + r.addr = v +} + +func (r *GetRequestBody) GetRaw() bool { + if r != nil { + return r.raw + } + + return false +} + +func (r *GetRequestBody) SetRaw(v bool) { + r.raw = v +} + +func (r *GetRequest) GetBody() *GetRequestBody { + if r != nil { + return r.body + } + + return nil +} + +func (r *GetRequest) SetBody(v *GetRequestBody) { + r.body = v +} + +func (r *GetObjectPartInit) GetObjectID() *refs.ObjectID { + if r != nil { + return r.id + } + + return nil +} + +func (r *GetObjectPartInit) SetObjectID(v *refs.ObjectID) { + r.id = v +} + +func (r *GetObjectPartInit) GetSignature() *refs.Signature { + if r != nil { + return r.sig + } + + return nil +} + +func (r *GetObjectPartInit) SetSignature(v *refs.Signature) { + r.sig = v +} + +func (r *GetObjectPartInit) GetHeader() *Header { + if r != nil { + return r.hdr + } + + return nil +} + +func (r *GetObjectPartInit) SetHeader(v *Header) { + r.hdr = v +} + +func (r *GetObjectPartInit) getObjectPart() {} + +func (r *GetObjectPartChunk) GetChunk() []byte { + if r != nil { + return r.chunk + } + + return nil +} + +func (r *GetObjectPartChunk) SetChunk(v []byte) { + r.chunk = v +} + +func (r *GetObjectPartChunk) getObjectPart() {} + +func (r *GetResponseBody) GetObjectPart() GetObjectPart { + if r != nil { + return r.objPart + } + + return nil +} + +func (r *GetResponseBody) SetObjectPart(v GetObjectPart) { + r.objPart = v +} + +func (r *GetResponse) GetBody() *GetResponseBody { + if r != nil { + return r.body + } + + return nil +} + +func (r *GetResponse) SetBody(v *GetResponseBody) { + r.body = v +} + +func (r *PutObjectPartInit) GetObjectID() *refs.ObjectID { + if r != nil { + return r.id + } + + return nil +} + +func (r *PutObjectPartInit) SetObjectID(v *refs.ObjectID) { + r.id = v +} + +func (r *PutObjectPartInit) GetSignature() *refs.Signature { + if r != nil { + return r.sig + } + + return nil +} + +func (r *PutObjectPartInit) SetSignature(v *refs.Signature) { + r.sig = v +} + +func (r *PutObjectPartInit) GetHeader() *Header { + if r != nil { + return r.hdr + } + + return nil +} + +func (r *PutObjectPartInit) SetHeader(v *Header) { + r.hdr = v +} + +func (r *PutObjectPartInit) GetCopiesNumber() []uint32 { + if r != nil { + return r.copyNum + } + + return nil +} + +func (r *PutObjectPartInit) SetCopiesNumber(v []uint32) { + r.copyNum = v +} + +func (r *PutObjectPartInit) putObjectPart() {} + +func (r *PutObjectPartChunk) GetChunk() []byte { + if r != nil { + return r.chunk + } + + return nil +} + +func (r *PutObjectPartChunk) SetChunk(v []byte) { + r.chunk = v +} + +func (r *PutObjectPartChunk) putObjectPart() {} + +func (r *PutRequestBody) GetObjectPart() PutObjectPart { + if r != nil { + return r.objPart + } + + return nil +} + +func (r *PutRequestBody) SetObjectPart(v PutObjectPart) { + r.objPart = v +} + +func (r *PutRequest) GetBody() *PutRequestBody { + if r != nil { + return r.body + } + + return nil +} + +func (r *PutRequest) SetBody(v *PutRequestBody) { + r.body = v +} + +func (r *PutResponseBody) GetObjectID() *refs.ObjectID { + if r != nil { + return r.id + } + + return nil +} + +func (r *PutResponseBody) SetObjectID(v *refs.ObjectID) { + r.id = v +} + +func (r *PutResponse) GetBody() *PutResponseBody { + if r != nil { + return r.body + } + + return nil +} + +func (r *PutResponse) SetBody(v *PutResponseBody) { + r.body = v +} + +func (r *DeleteRequestBody) GetAddress() *refs.Address { + if r != nil { + return r.addr + } + + return nil +} + +func (r *DeleteRequestBody) SetAddress(v *refs.Address) { + r.addr = v +} + +func (r *DeleteRequest) GetBody() *DeleteRequestBody { + if r != nil { + return r.body + } + + return nil +} + +func (r *DeleteRequest) SetBody(v *DeleteRequestBody) { + r.body = v +} + +// GetTombstone returns tombstone address. +func (r *DeleteResponseBody) GetTombstone() *refs.Address { + if r != nil { + return r.tombstone + } + + return nil +} + +// SetTombstone sets tombstone address. +func (r *DeleteResponseBody) SetTombstone(v *refs.Address) { + r.tombstone = v +} + +func (r *DeleteResponse) GetBody() *DeleteResponseBody { + if r != nil { + return r.body + } + + return nil +} + +func (r *DeleteResponse) SetBody(v *DeleteResponseBody) { + r.body = v +} + +func (r *HeadRequestBody) GetAddress() *refs.Address { + if r != nil { + return r.addr + } + + return nil +} + +func (r *HeadRequestBody) SetAddress(v *refs.Address) { + r.addr = v +} + +func (r *HeadRequestBody) GetMainOnly() bool { + if r != nil { + return r.mainOnly + } + + return false +} + +func (r *HeadRequestBody) SetMainOnly(v bool) { + r.mainOnly = v +} + +func (r *HeadRequestBody) GetRaw() bool { + if r != nil { + return r.raw + } + + return false +} + +func (r *HeadRequestBody) SetRaw(v bool) { + r.raw = v +} + +func (r *HeadRequest) GetBody() *HeadRequestBody { + if r != nil { + return r.body + } + + return nil +} + +func (r *HeadRequest) SetBody(v *HeadRequestBody) { + r.body = v +} + +func (r *HeadResponseBody) GetHeaderPart() GetHeaderPart { + if r != nil { + return r.hdrPart + } + + return nil +} + +func (r *HeadResponseBody) SetHeaderPart(v GetHeaderPart) { + r.hdrPart = v +} + +func (r *HeadResponse) GetBody() *HeadResponseBody { + if r != nil { + return r.body + } + + return nil +} + +func (r *HeadResponse) SetBody(v *HeadResponseBody) { + r.body = v +} + +func (f *SearchFilter) GetMatchType() MatchType { + if f != nil { + return f.matchType + } + + return MatchUnknown +} + +func (f *SearchFilter) SetMatchType(v MatchType) { + f.matchType = v +} + +func (f *SearchFilter) GetKey() string { + if f != nil { + return f.key + } + + return "" +} + +func (f *SearchFilter) SetKey(v string) { + f.key = v +} + +func (f *SearchFilter) GetValue() string { + if f != nil { + return f.val + } + + return "" +} + +func (f *SearchFilter) SetValue(v string) { + f.val = v +} + +func (r *SearchRequestBody) GetContainerID() *refs.ContainerID { + if r != nil { + return r.cid + } + + return nil +} + +func (r *SearchRequestBody) SetContainerID(v *refs.ContainerID) { + r.cid = v +} + +func (r *SearchRequestBody) GetVersion() uint32 { + if r != nil { + return r.version + } + + return 0 +} + +func (r *SearchRequestBody) SetVersion(v uint32) { + r.version = v +} + +func (r *SearchRequestBody) GetFilters() []SearchFilter { + if r != nil { + return r.filters + } + + return nil +} + +func (r *SearchRequestBody) SetFilters(v []SearchFilter) { + r.filters = v +} + +func (r *SearchRequest) GetBody() *SearchRequestBody { + if r != nil { + return r.body + } + + return nil +} + +func (r *SearchRequest) SetBody(v *SearchRequestBody) { + r.body = v +} + +func (r *SearchResponseBody) GetIDList() []refs.ObjectID { + if r != nil { + return r.idList + } + + return nil +} + +func (r *SearchResponseBody) SetIDList(v []refs.ObjectID) { + r.idList = v +} + +func (r *SearchResponse) GetBody() *SearchResponseBody { + if r != nil { + return r.body + } + + return nil +} + +func (r *SearchResponse) SetBody(v *SearchResponseBody) { + r.body = v +} + +func (r *Range) GetOffset() uint64 { + if r != nil { + return r.off + } + + return 0 +} + +func (r *Range) SetOffset(v uint64) { + r.off = v +} + +func (r *Range) GetLength() uint64 { + if r != nil { + return r.len + } + + return 0 +} + +func (r *Range) SetLength(v uint64) { + r.len = v +} + +func (r *GetRangeRequestBody) GetAddress() *refs.Address { + if r != nil { + return r.addr + } + + return nil +} + +func (r *GetRangeRequestBody) SetAddress(v *refs.Address) { + r.addr = v +} + +func (r *GetRangeRequestBody) GetRange() *Range { + if r != nil { + return r.rng + } + + return nil +} + +func (r *GetRangeRequestBody) SetRange(v *Range) { + r.rng = v +} + +func (r *GetRangeRequestBody) GetRaw() bool { + if r != nil { + return r.raw + } + + return false +} + +func (r *GetRangeRequestBody) SetRaw(v bool) { + r.raw = v +} + +func (r *GetRangeRequest) GetBody() *GetRangeRequestBody { + if r != nil { + return r.body + } + + return nil +} + +func (r *GetRangeRequest) SetBody(v *GetRangeRequestBody) { + r.body = v +} + +func (r *GetRangePartChunk) GetChunk() []byte { + if r != nil { + return r.chunk + } + + return nil +} + +func (r *GetRangePartChunk) SetChunk(v []byte) { + r.chunk = v +} + +func (r *GetRangePartChunk) getRangePart() {} + +func (r *GetRangeResponseBody) GetRangePart() GetRangePart { + if r != nil { + return r.rngPart + } + + return nil +} + +func (r *GetRangeResponseBody) SetRangePart(v GetRangePart) { + r.rngPart = v +} + +func (r *GetRangeResponse) GetBody() *GetRangeResponseBody { + if r != nil { + return r.body + } + + return nil +} + +func (r *GetRangeResponse) SetBody(v *GetRangeResponseBody) { + r.body = v +} + +func (r *GetRangeHashRequestBody) GetAddress() *refs.Address { + if r != nil { + return r.addr + } + + return nil +} + +func (r *GetRangeHashRequestBody) SetAddress(v *refs.Address) { + r.addr = v +} + +func (r *GetRangeHashRequestBody) GetRanges() []Range { + if r != nil { + return r.rngs + } + + return nil +} + +func (r *GetRangeHashRequestBody) SetRanges(v []Range) { + r.rngs = v +} + +func (r *GetRangeHashRequestBody) GetSalt() []byte { + if r != nil { + return r.salt + } + + return nil +} + +func (r *GetRangeHashRequestBody) SetSalt(v []byte) { + r.salt = v +} + +func (r *GetRangeHashRequestBody) GetType() refs.ChecksumType { + if r != nil { + return r.typ + } + + return refs.UnknownChecksum +} + +func (r *GetRangeHashRequestBody) SetType(v refs.ChecksumType) { + r.typ = v +} + +func (r *GetRangeHashRequest) GetBody() *GetRangeHashRequestBody { + if r != nil { + return r.body + } + + return nil +} + +func (r *GetRangeHashRequest) SetBody(v *GetRangeHashRequestBody) { + r.body = v +} + +func (r *GetRangeHashResponseBody) GetType() refs.ChecksumType { + if r != nil { + return r.typ + } + + return refs.UnknownChecksum +} + +func (r *GetRangeHashResponseBody) SetType(v refs.ChecksumType) { + r.typ = v +} + +func (r *GetRangeHashResponseBody) GetHashList() [][]byte { + if r != nil { + return r.hashList + } + + return nil +} + +func (r *GetRangeHashResponseBody) SetHashList(v [][]byte) { + r.hashList = v +} + +func (r *GetRangeHashResponse) GetBody() *GetRangeHashResponseBody { + if r != nil { + return r.body + } + + return nil +} + +func (r *GetRangeHashResponse) SetBody(v *GetRangeHashResponseBody) { + r.body = v +} + +func (r *PutSingleRequest) GetBody() *PutSingleRequestBody { + if r != nil { + return r.body + } + + return nil +} + +func (r *PutSingleRequest) SetBody(v *PutSingleRequestBody) { + r.body = v +} + +func (b *PutSingleRequestBody) GetObject() *Object { + if b == nil { + return nil + } + return b.object +} + +func (b *PutSingleRequestBody) SetObject(o *Object) { + b.object = o +} + +func (b *PutSingleRequestBody) GetCopiesNumber() []uint32 { + if b == nil { + return nil + } + return b.copyNum +} + +func (b *PutSingleRequestBody) SetCopiesNumber(v []uint32) { + b.copyNum = v +} + +func (r *PutSingleResponse) GetBody() *PutSingleResponseBody { + if r != nil { + return r.body + } + + return nil +} + +func (r *PutSingleResponse) SetBody(v *PutSingleResponseBody) { + r.body = v +} + +func (r *PatchRequest) GetBody() *PatchRequestBody { + if r != nil { + return r.body + } + + return nil +} + +func (r *PatchRequest) SetBody(v *PatchRequestBody) { + r.body = v +} + +func (r *PatchRequestBody) GetAddress() *refs.Address { + if r != nil { + return r.address + } + + return nil +} + +func (r *PatchRequestBody) SetAddress(addr *refs.Address) { + r.address = addr +} + +func (r *PatchRequestBody) GetNewAttributes() []Attribute { + if r != nil { + return r.newAttributes + } + + return nil +} + +func (r *PatchRequestBody) SetNewAttributes(attrs []Attribute) { + r.newAttributes = attrs +} + +func (r *PatchRequestBody) GetReplaceAttributes() bool { + if r != nil { + return r.replaceAttributes + } + + return false +} + +func (r *PatchRequestBody) SetReplaceAttributes(replace bool) { + r.replaceAttributes = replace +} + +func (r *PatchRequestBody) GetPatch() *PatchRequestBodyPatch { + if r != nil { + return r.patch + } + + return nil +} + +func (r *PatchRequestBody) SetPatch(patch *PatchRequestBodyPatch) { + r.patch = patch +} + +func (r *PatchResponse) GetBody() *PatchResponseBody { + if r != nil { + return r.Body + } + + return nil +} + +func (r *PatchResponse) SetBody(v *PatchResponseBody) { + r.Body = v +} + +func (r *PatchResponseBody) GetObjectID() *refs.ObjectID { + if r != nil { + return r.ObjectID + } + + return nil +} + +func (r *PatchResponseBody) SetObjectID(objectID *refs.ObjectID) { + r.ObjectID = objectID +} + +func (r *PatchRequestBodyPatch) GetChunk() []byte { + if r != nil { + return r.Chunk + } + + return nil +} + +func (r *PatchRequestBodyPatch) GetRange() *Range { + if r != nil { + return r.Range + } + + return nil +} + +func (s *ECInfo) getObjectPart() {} + +func (s *ECInfo) getHeaderPart() {} + +func (s *ECInfo) getRangePart() {} diff --git a/api/refs/bench_test.go b/api/refs/bench_test.go new file mode 100644 index 0000000..40784c6 --- /dev/null +++ b/api/refs/bench_test.go @@ -0,0 +1,53 @@ +package refs + +import ( + "math/rand" + "strconv" + "testing" +) + +func BenchmarkObjectIDSlice(b *testing.B) { + for _, size := range []int{0, 1, 50} { + b.Run(strconv.Itoa(size)+" elements", func(b *testing.B) { + benchmarkObjectIDSlice(b, size) + }) + } +} + +func benchmarkObjectIDSlice(b *testing.B, size int) { + ids := make([]ObjectID, size) + for i := range ids { + ids[i].val = make([]byte, 32) + rand.Read(ids[i].val) + } + raw := ObjectIDListToGRPCMessage(ids) + + b.Run("to grpc message", func(b *testing.B) { + b.ReportAllocs() + for range b.N { + raw := ObjectIDListToGRPCMessage(ids) + if len(raw) != len(ids) { + b.FailNow() + } + } + }) + b.Run("from grpc message", func(b *testing.B) { + b.ReportAllocs() + for range b.N { + ids, err := ObjectIDListFromGRPCMessage(raw) + if err != nil || len(raw) != len(ids) { + b.FailNow() + } + } + }) + b.Run("marshal", func(b *testing.B) { + b.ReportAllocs() + for range b.N { + buf := make([]byte, ObjectIDNestedListSize(1, ids)) + n := ObjectIDNestedListMarshal(1, buf, ids) + if n != len(buf) { + b.FailNow() + } + } + }) +} diff --git a/api/refs/convert.go b/api/refs/convert.go new file mode 100644 index 0000000..8e72c37 --- /dev/null +++ b/api/refs/convert.go @@ -0,0 +1,264 @@ +package refs + +import ( + refs "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" +) + +func (o *OwnerID) ToGRPCMessage() grpc.Message { + var m *refs.OwnerID + + if o != nil { + m = new(refs.OwnerID) + + m.SetValue(o.val) + } + + return m +} + +func (o *OwnerID) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*refs.OwnerID) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + o.val = v.GetValue() + + return nil +} + +func (c *ContainerID) ToGRPCMessage() grpc.Message { + var m *refs.ContainerID + + if c != nil { + m = new(refs.ContainerID) + + m.SetValue(c.val) + } + + return m +} + +func (c *ContainerID) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*refs.ContainerID) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + c.val = v.GetValue() + + return nil +} + +func ContainerIDsToGRPCMessage(ids []ContainerID) (res []refs.ContainerID) { + if ids != nil { + res = make([]refs.ContainerID, 0, len(ids)) + + for i := range ids { + res = append(res, *ids[i].ToGRPCMessage().(*refs.ContainerID)) + } + } + + return +} + +func ContainerIDsFromGRPCMessage(idsV2 []refs.ContainerID) (res []ContainerID, err error) { + if idsV2 != nil { + res = make([]ContainerID, len(idsV2)) + + for i := range idsV2 { + err = res[i].FromGRPCMessage(&idsV2[i]) + if err != nil { + return + } + } + } + + return +} + +func (o *ObjectID) ToGRPCMessage() grpc.Message { + var m *refs.ObjectID + + if o != nil { + m = new(refs.ObjectID) + + m.SetValue(o.val) + } + + return m +} + +func (o *ObjectID) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*refs.ObjectID) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + o.val = v.GetValue() + + return nil +} + +func ObjectIDListToGRPCMessage(ids []ObjectID) (res []refs.ObjectID) { + if ids != nil { + res = make([]refs.ObjectID, 0, len(ids)) + + for i := range ids { + res = append(res, *ids[i].ToGRPCMessage().(*refs.ObjectID)) + } + } + + return +} + +func ObjectIDListFromGRPCMessage(idsV2 []refs.ObjectID) (res []ObjectID, err error) { + if idsV2 != nil { + res = make([]ObjectID, len(idsV2)) + + for i := range idsV2 { + err = res[i].FromGRPCMessage(&idsV2[i]) + if err != nil { + return + } + } + } + + return +} + +func (a *Address) ToGRPCMessage() grpc.Message { + var m *refs.Address + + if a != nil { + m = new(refs.Address) + + m.SetContainerId(a.cid.ToGRPCMessage().(*refs.ContainerID)) + m.SetObjectId(a.oid.ToGRPCMessage().(*refs.ObjectID)) + } + + return m +} + +func (a *Address) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*refs.Address) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + cid := v.GetContainerId() + if cid == nil { + a.cid = nil + } else { + if a.cid == nil { + a.cid = new(ContainerID) + } + + err = a.cid.FromGRPCMessage(cid) + if err != nil { + return err + } + } + + oid := v.GetObjectId() + if oid == nil { + a.oid = nil + } else { + if a.oid == nil { + a.oid = new(ObjectID) + } + + err = a.oid.FromGRPCMessage(oid) + } + + return err +} + +func ChecksumTypeToGRPC(t ChecksumType) refs.ChecksumType { + return refs.ChecksumType(t) +} + +func ChecksumTypeFromGRPC(t refs.ChecksumType) ChecksumType { + return ChecksumType(t) +} + +func (c *Checksum) ToGRPCMessage() grpc.Message { + var m *refs.Checksum + + if c != nil { + m = new(refs.Checksum) + + m.SetType(ChecksumTypeToGRPC(c.typ)) + m.SetSum(c.sum) + } + + return m +} + +func (c *Checksum) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*refs.Checksum) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + c.typ = ChecksumTypeFromGRPC(v.GetType()) + c.sum = v.GetSum() + + return nil +} + +func (v *Version) ToGRPCMessage() grpc.Message { + var m *refs.Version + + if v != nil { + m = new(refs.Version) + + m.SetMajor(v.major) + m.SetMinor(v.minor) + } + + return m +} + +func (v *Version) FromGRPCMessage(m grpc.Message) error { + ver, ok := m.(*refs.Version) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + v.major = ver.GetMajor() + v.minor = ver.GetMinor() + + return nil +} + +func (s *Signature) ToGRPCMessage() grpc.Message { + var m *refs.Signature + + if s != nil { + m = new(refs.Signature) + + m.SetKey(s.key) + m.SetSign(s.sign) + m.SetScheme(refs.SignatureScheme(s.scheme)) + } + + return m +} + +func (s *Signature) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*refs.Signature) + if !ok { + return message.NewUnexpectedMessageType(m, s) + } + + s.key = v.GetKey() + s.sign = v.GetSign() + s.scheme = SignatureScheme(v.GetScheme()) + + return nil +} diff --git a/api/refs/grpc/types_frostfs.pb.go b/api/refs/grpc/types_frostfs.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..f0a10f34ece47dad678150c8cf4b65d5fe7e6a68 GIT binary patch literal 31179 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 if `opaque` is not empty, then it is supposed that URI + // is in `host:port` format + if uri.Host == "" { + uri.Host = uri.Scheme + uri.Scheme = grpcScheme // assume GRPC by default + if uri.Opaque != "" { + uri.Host = net.JoinHostPort(uri.Host, uri.Opaque) + } + } + + switch uri.Scheme { + case grpcTLSScheme, grpcScheme: + default: + return "", false, fmt.Errorf("unsupported scheme: %s", uri.Scheme) + } + + return uri.Host, uri.Scheme == grpcTLSScheme, nil +} diff --git a/api/rpc/client/flows.go b/api/rpc/client/flows.go new file mode 100644 index 0000000..671c679 --- /dev/null +++ b/api/rpc/client/flows.go @@ -0,0 +1,124 @@ +package client + +import ( + "errors" + "io" + "sync" + + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/common" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" +) + +// SendUnary initializes communication session by RPC info, performs unary RPC +// and closes the session. +func SendUnary(cli *Client, info common.CallMethodInfo, req, resp message.Message, opts ...CallOption) error { + rw, err := cli.Init(info, opts...) + if err != nil { + return err + } + + err = rw.WriteMessage(req) + if err != nil { + return err + } + + err = rw.ReadMessage(resp) + if err != nil { + return err + } + + return rw.Close() +} + +// MessageWriterCloser wraps MessageWriter +// and io.Closer interfaces. +type MessageWriterCloser interface { + MessageWriter + io.Closer +} + +type clientStreamWriterCloser struct { + MessageReadWriter + + resp message.Message +} + +func (c *clientStreamWriterCloser) Close() error { + err := c.MessageReadWriter.Close() + if err != nil { + return err + } + + return c.ReadMessage(c.resp) +} + +// OpenClientStream initializes communication session by RPC info, opens client-side stream +// and returns its interface. +// +// All stream writes must be performed before the closing. Close must be called once. +func OpenClientStream(cli *Client, info common.CallMethodInfo, resp message.Message, opts ...CallOption) (MessageWriterCloser, error) { + rw, err := cli.Init(info, opts...) + if err != nil { + return nil, err + } + + return &clientStreamWriterCloser{ + MessageReadWriter: rw, + resp: resp, + }, nil +} + +// MessageReaderCloser wraps MessageReader +// and io.Closer interface. +type MessageReaderCloser interface { + MessageReader + io.Closer +} + +type serverStreamReaderCloser struct { + rw MessageReadWriter + + once sync.Once + + req message.Message +} + +func (s *serverStreamReaderCloser) ReadMessage(msg message.Message) error { + var err error + + s.once.Do(func() { + err = s.rw.WriteMessage(s.req) + }) + + if err != nil { + return err + } + + err = s.rw.ReadMessage(msg) + if !errors.Is(err, io.EOF) { + return err + } + + err = s.rw.Close() + if err != nil { + return err + } + + return io.EOF +} + +// OpenServerStream initializes communication session by RPC info, opens server-side stream +// and returns its interface. +// +// All stream reads must be performed before the closing. Close must be called once. +func OpenServerStream(cli *Client, info common.CallMethodInfo, req message.Message, opts ...CallOption) (MessageReader, error) { + rw, err := cli.Init(info, opts...) + if err != nil { + return nil, err + } + + return &serverStreamReaderCloser{ + rw: rw, + req: req, + }, nil +} diff --git a/api/rpc/client/init.go b/api/rpc/client/init.go new file mode 100644 index 0000000..706e6a9 --- /dev/null +++ b/api/rpc/client/init.go @@ -0,0 +1,69 @@ +package client + +import ( + "context" + "io" + + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/common" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + "google.golang.org/grpc" +) + +// MessageReader is an interface of the Message reader. +type MessageReader interface { + // ReadMessage reads the next Message. + // + // Returns io.EOF if there are no more messages to read. + // ReadMessage should not be called after io.EOF occasion. + ReadMessage(message.Message) error +} + +// MessageWriter is an interface of the Message writer. +type MessageWriter interface { + // WriteMessage writers the next Message. + // + // WriteMessage should not be called after any error. + WriteMessage(message.Message) error +} + +// MessageReadWriter is a component interface +// for transmitting raw Protobuf messages. +type MessageReadWriter interface { + MessageReader + MessageWriter + + // Closes the communication session. + // + // All calls to send/receive messages must be done before closing. + io.Closer +} + +// Init initiates a messaging session and returns the interface for message transmitting. +func (c *Client) Init(info common.CallMethodInfo, opts ...CallOption) (MessageReadWriter, error) { + prm := defaultCallParameters() + + for _, opt := range opts { + opt(prm) + } + + if err := c.openGRPCConn(prm.ctx, prm.dialer); err != nil { + return nil, err + } + + ctx, cancel := context.WithCancel(prm.ctx) + stream, err := c.conn.NewStream(ctx, &grpc.StreamDesc{ + StreamName: info.Name, + ServerStreams: info.ServerStream(), + ClientStreams: info.ClientStream(), + }, toMethodName(info)) + if err != nil { + cancel() + return nil, err + } + + return &streamWrapper{ + ClientStream: stream, + cancel: cancel, + timeout: c.rwTimeout, + }, nil +} diff --git a/api/rpc/client/options.go b/api/rpc/client/options.go new file mode 100644 index 0000000..5711cd4 --- /dev/null +++ b/api/rpc/client/options.go @@ -0,0 +1,129 @@ +package client + +import ( + "crypto/tls" + "time" + + "google.golang.org/grpc" + "google.golang.org/grpc/credentials/insecure" +) + +const ( + grpcScheme = "grpc" + grpcTLSScheme = "grpcs" +) + +// Option is a Client's option. +type Option func(*cfg) + +type cfg struct { + addr string + + dialTimeout time.Duration + rwTimeout time.Duration + + tlsCfg *tls.Config + grpcDialOpts []grpc.DialOption + + conn Conn +} + +const ( + defaultDialTimeout = 5 * time.Second + defaultRWTimeout = 1 * time.Minute +) + +func (c *cfg) initDefault() { + c.dialTimeout = defaultDialTimeout + c.rwTimeout = defaultRWTimeout + c.grpcDialOpts = []grpc.DialOption{ + grpc.WithTransportCredentials(insecure.NewCredentials()), + } +} + +// WithNetworkAddress returns option to specify +// network address of the remote server. +// +// Ignored if WithGRPCConn is provided. +func WithNetworkAddress(v string) Option { + return func(c *cfg) { + if v != "" { + c.addr = v + } + } +} + +// WithNetworkURIAddress combines WithNetworkAddress and WithTLSCfg options +// based on arguments. +// +// Do not use along with WithNetworkAddress and WithTLSCfg. +// +// Ignored if WithGRPCConn is provided. +func WithNetworkURIAddress(addr string, tlsCfg *tls.Config) []Option { + host, isTLS, err := ParseURI(addr) + if err != nil { + return nil + } + + opts := make([]Option, 2) + opts[0] = WithNetworkAddress(host) + if isTLS { + if tlsCfg == nil { + tlsCfg = &tls.Config{} + } + opts[1] = WithTLSCfg(tlsCfg) + } else { + opts[1] = WithTLSCfg(nil) + } + + return opts +} + +// WithDialTimeout returns option to specify +// dial timeout of the remote server connection. +// +// Ignored if WithGRPCConn is provided. +func WithDialTimeout(v time.Duration) Option { + return func(c *cfg) { + if v > 0 { + c.dialTimeout = v + } + } +} + +// WithRWTimeout returns option to specify timeout +// for reading and writing single gRPC message. +func WithRWTimeout(v time.Duration) Option { + return func(c *cfg) { + if v > 0 { + c.rwTimeout = v + } + } +} + +// WithTLSCfg returns option to specify +// TLS configuration. +// +// Ignored if WithGRPCConn is provided. +func WithTLSCfg(v *tls.Config) Option { + return func(c *cfg) { + c.tlsCfg = v + } +} + +// WithGRPCConn returns option to specify +// gRPC virtual connection. +func WithGRPCConn(v Conn) Option { + return func(c *cfg) { + if v != nil { + c.conn = v + } + } +} + +// WithGRPCDialOptions returns an option to specify grpc.DialOption. +func WithGRPCDialOptions(opts []grpc.DialOption) Option { + return func(c *cfg) { + c.grpcDialOpts = append(c.grpcDialOpts, opts...) + } +} diff --git a/api/rpc/client/options_test.go b/api/rpc/client/options_test.go new file mode 100644 index 0000000..56704b6 --- /dev/null +++ b/api/rpc/client/options_test.go @@ -0,0 +1,197 @@ +package client + +import ( + "crypto/tls" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestWithNetworkURIAddress(t *testing.T) { + hostPort := "frostfs.example.com:8080" + apiPort := "127.0.0.1:8080" + serverName := "testServer" + + testCases := []struct { + uri string + tlsConfig *tls.Config + + wantHost string + wantTLS bool + }{ + { + uri: grpcScheme + "://" + hostPort, + tlsConfig: nil, + wantHost: "frostfs.example.com:8080", + wantTLS: false, + }, + { + uri: grpcScheme + "://" + hostPort, + tlsConfig: &tls.Config{}, + wantHost: "frostfs.example.com:8080", + wantTLS: false, + }, + { + uri: grpcTLSScheme + "://" + hostPort, + tlsConfig: nil, + wantHost: "frostfs.example.com:8080", + wantTLS: true, + }, + { + uri: grpcTLSScheme + "://" + hostPort, + tlsConfig: &tls.Config{ServerName: serverName}, + wantHost: "frostfs.example.com:8080", + wantTLS: true, + }, + { + uri: "wrongScheme://" + hostPort, + tlsConfig: nil, + wantHost: "", + wantTLS: false, + }, + { + uri: "impossibleToParseIt", + tlsConfig: nil, + wantHost: "impossibleToParseIt", + wantTLS: false, + }, + { + uri: hostPort, + tlsConfig: nil, + wantHost: hostPort, + wantTLS: false, + }, + { + uri: apiPort, + tlsConfig: nil, + wantHost: apiPort, + wantTLS: false, + }, + } + + for _, test := range testCases { + cfg := &cfg{} + opts := WithNetworkURIAddress(test.uri, test.tlsConfig) + + for _, opt := range opts { + opt(cfg) + } + + require.Equal(t, test.wantHost, cfg.addr, test.uri) + require.Equal(t, test.wantTLS, cfg.tlsCfg != nil, test.uri) + // check if custom tlsConfig was applied + if test.tlsConfig != nil && test.wantTLS { + require.Equal(t, test.tlsConfig.ServerName, cfg.tlsCfg.ServerName, test.uri) + } + } +} + +func Test_WithNetworkAddress_WithTLS_WithNetworkURIAddress(t *testing.T) { + addr1, addr2 := "example1.com:8080", "example2.com:8080" + + testCases := []struct { + addr string + withTLS bool + + uri string + + wantHost string + wantTLS bool + }{ + { + addr: addr1, + withTLS: true, + + uri: grpcScheme + "://" + addr2, + + wantHost: addr2, + wantTLS: false, + }, + { + addr: addr1, + withTLS: false, + + uri: grpcTLSScheme + "://" + addr2, + + wantHost: addr2, + wantTLS: true, + }, + } + + for _, test := range testCases { + // order: + // 1. WithNetworkAddress + // 2. WithTLSCfg(if test.withTLS == true) + // 3. WithNetworkURIAddress + config := &cfg{} + opts := []Option{WithNetworkAddress(test.addr)} + + if test.withTLS { + opts = append(opts, WithTLSCfg(&tls.Config{})) + } + + opts = append(opts, WithNetworkURIAddress(test.uri, nil)...) + + for _, opt := range opts { + opt(config) + } + + require.Equal(t, test.wantHost, config.addr, test.addr) + require.Equal(t, test.wantTLS, config.tlsCfg != nil, test.addr) + } +} + +func Test_WithNetworkURIAddress_WithTLS_WithNetworkAddress(t *testing.T) { + addr1, addr2 := "example1.com:8080", "example2.com:8080" + + testCases := []struct { + addr string + withTLS bool + + uri string + + wantHost string + wantTLS bool + }{ + { + uri: grpcScheme + "://" + addr1, + + addr: addr2, + withTLS: true, + + wantHost: addr2, + wantTLS: true, + }, + { + uri: grpcTLSScheme + "://" + addr1, + + addr: addr2, + withTLS: false, + + wantHost: addr2, + wantTLS: true, + }, + } + + for _, test := range testCases { + // order: + // 1. WithNetworkURIAddress + // 2. WithNetworkAddress + // 3. WithTLSCfg(if test.withTLS == true) + config := &cfg{} + opts := WithNetworkURIAddress(test.uri, nil) + + opts = append(opts, WithNetworkAddress(test.addr)) + + if test.withTLS { + opts = append(opts, WithTLSCfg(&tls.Config{})) + } + + for _, opt := range opts { + opt(config) + } + + require.Equal(t, test.wantHost, config.addr, test.uri) + require.Equal(t, test.wantTLS, config.tlsCfg != nil, test.uri) + } +} diff --git a/api/rpc/client/stream_wrapper.go b/api/rpc/client/stream_wrapper.go new file mode 100644 index 0000000..4c7bb1f --- /dev/null +++ b/api/rpc/client/stream_wrapper.go @@ -0,0 +1,58 @@ +package client + +import ( + "context" + "time" + + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + "google.golang.org/grpc" +) + +type streamWrapper struct { + grpc.ClientStream + timeout time.Duration + cancel context.CancelFunc +} + +func (w streamWrapper) ReadMessage(m message.Message) error { + // Can be optimized: we can create blank message here. + gm := m.ToGRPCMessage() + + err := w.withTimeout(func() error { + return w.ClientStream.RecvMsg(gm) + }) + if err != nil { + return err + } + + return m.FromGRPCMessage(gm) +} + +func (w streamWrapper) WriteMessage(m message.Message) error { + return w.withTimeout(func() error { + return w.ClientStream.SendMsg(m.ToGRPCMessage()) + }) +} + +func (w *streamWrapper) Close() error { + return w.withTimeout(w.ClientStream.CloseSend) +} + +func (w *streamWrapper) withTimeout(closure func() error) error { + ch := make(chan error, 1) + go func() { + ch <- closure() + close(ch) + }() + + tt := time.NewTimer(w.timeout) + + select { + case err := <-ch: + tt.Stop() + return err + case <-tt.C: + w.cancel() + return context.DeadlineExceeded + } +} diff --git a/api/rpc/client/util.go b/api/rpc/client/util.go new file mode 100644 index 0000000..3d68b95 --- /dev/null +++ b/api/rpc/client/util.go @@ -0,0 +1,13 @@ +package client + +import ( + "fmt" + + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/common" +) + +const methodNameFmt = "/%s/%s" + +func toMethodName(p common.CallMethodInfo) string { + return fmt.Sprintf(methodNameFmt, p.Service, p.Name) +} diff --git a/api/rpc/common.go b/api/rpc/common.go new file mode 100644 index 0000000..8177694 --- /dev/null +++ b/api/rpc/common.go @@ -0,0 +1,10 @@ +package rpc + +const ( + // serviceNamePrefix is still used in "old" services but should be + // considered as deprecated. Since new services use "frostfs" root, + // `frostfsServiceNamePrefix` must be used for their rpc interface. + serviceNamePrefix = "neo.fs.v2." + + frostfsServiceNamePrefix = "frostfs.v2." +) diff --git a/api/rpc/common/call.go b/api/rpc/common/call.go new file mode 100644 index 0000000..bc3410a --- /dev/null +++ b/api/rpc/common/call.go @@ -0,0 +1,75 @@ +package common + +type callType uint8 + +const ( + _ callType = iota + callUnary + callClientStream + callServerStream + callBidirStream +) + +// CallMethodInfo is an information about the RPC. +type CallMethodInfo struct { + // Name of the service. + Service string + + // Name of the RPC. + Name string + + t callType +} + +// ServerStream checks if CallMethodInfo contains +// information about the server-side streaming RPC. +func (c CallMethodInfo) ServerStream() bool { + return c.t == callServerStream || c.t == callBidirStream +} + +// ClientStream checks if CallMethodInfo contains +// information about the client-side streaming RPC. +func (c CallMethodInfo) ClientStream() bool { + return c.t == callClientStream || c.t == callBidirStream +} + +func (c *CallMethodInfo) setCommon(service, name string) { + c.Service = service + c.Name = name +} + +// CallMethodInfoUnary returns CallMethodInfo structure +// initialized for the unary RPC. +func CallMethodInfoUnary(service, name string) (info CallMethodInfo) { + info.setCommon(service, name) + info.t = callUnary + + return +} + +// CallMethodInfoClientStream returns CallMethodInfo structure +// initialized for the client-side streaming RPC. +func CallMethodInfoClientStream(service, name string) (info CallMethodInfo) { + info.setCommon(service, name) + info.t = callClientStream + + return +} + +// CallMethodInfoServerStream returns CallMethodInfo structure +// initialized for the server-side streaming RPC. +func CallMethodInfoServerStream(service, name string) (info CallMethodInfo) { + info.setCommon(service, name) + info.t = callServerStream + + return +} + +// CallMethodInfoBidirectionalStream returns CallMethodInfo structure +// initialized for the bidirectional streaming RPC. +func CallMethodInfoBidirectionalStream(service, name string) (info CallMethodInfo) { + info.setCommon(service, name) + info.t = callBidirStream + + return +} diff --git a/api/rpc/common/call_test.go b/api/rpc/common/call_test.go new file mode 100644 index 0000000..eb88b69 --- /dev/null +++ b/api/rpc/common/call_test.go @@ -0,0 +1,49 @@ +package common_test + +import ( + "testing" + + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/common" + "github.com/stretchr/testify/require" +) + +const ( + testServiceName = "test service" + testRPCName = "test RPC" +) + +func TestCallMethodInfoUnary(t *testing.T) { + i := common.CallMethodInfoUnary(testServiceName, testRPCName) + + require.Equal(t, testServiceName, i.Service) + require.Equal(t, testRPCName, i.Name) + require.False(t, i.ClientStream()) + require.False(t, i.ServerStream()) +} + +func TestCallMethodInfoServerStream(t *testing.T) { + i := common.CallMethodInfoServerStream(testServiceName, testRPCName) + + require.Equal(t, testServiceName, i.Service) + require.Equal(t, testRPCName, i.Name) + require.False(t, i.ClientStream()) + require.True(t, i.ServerStream()) +} + +func TestCallMethodInfoClientStream(t *testing.T) { + i := common.CallMethodInfoClientStream(testServiceName, testRPCName) + + require.Equal(t, testServiceName, i.Service) + require.Equal(t, testRPCName, i.Name) + require.True(t, i.ClientStream()) + require.False(t, i.ServerStream()) +} + +func TestCallMethodInfoBidirectionalStream(t *testing.T) { + i := common.CallMethodInfoBidirectionalStream(testServiceName, testRPCName) + + require.Equal(t, testServiceName, i.Service) + require.Equal(t, testRPCName, i.Name) + require.True(t, i.ClientStream()) + require.True(t, i.ServerStream()) +} diff --git a/api/rpc/container.go b/api/rpc/container.go new file mode 100644 index 0000000..9ba5c99 --- /dev/null +++ b/api/rpc/container.go @@ -0,0 +1,82 @@ +package rpc + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/common" +) + +const serviceContainer = serviceNamePrefix + "container.ContainerService" + +const ( + rpcContainerPut = "Put" + rpcContainerGet = "Get" + rpcContainerDel = "Delete" + rpcContainerList = "List" + rpcContainerGetEACL = "GetExtendedACL" + rpcContainerUsedSpace = "AnnounceUsedSpace" +) + +// PutContainer executes ContainerService.Put RPC. +func PutContainer( + cli *client.Client, + req *container.PutRequest, + opts ...client.CallOption, +) (*container.PutResponse, error) { + resp := new(container.PutResponse) + + err := client.SendUnary(cli, common.CallMethodInfoUnary(serviceContainer, rpcContainerPut), req, resp, opts...) + if err != nil { + return nil, err + } + + return resp, nil +} + +// GetContainer executes ContainerService.Get RPC. +func GetContainer( + cli *client.Client, + req *container.GetRequest, + opts ...client.CallOption, +) (*container.GetResponse, error) { + resp := new(container.GetResponse) + + err := client.SendUnary(cli, common.CallMethodInfoUnary(serviceContainer, rpcContainerGet), req, resp, opts...) + if err != nil { + return nil, err + } + + return resp, nil +} + +// DeleteContainer executes ContainerService.Delete RPC. +func DeleteContainer( + cli *client.Client, + req *container.DeleteRequest, + opts ...client.CallOption, +) (*container.PutResponse, error) { + resp := new(container.PutResponse) + + err := client.SendUnary(cli, common.CallMethodInfoUnary(serviceContainer, rpcContainerDel), req, resp, opts...) + if err != nil { + return nil, err + } + + return resp, nil +} + +// ListContainers executes ContainerService.List RPC. +func ListContainers( + cli *client.Client, + req *container.ListRequest, + opts ...client.CallOption, +) (*container.ListResponse, error) { + resp := new(container.ListResponse) + + err := client.SendUnary(cli, common.CallMethodInfoUnary(serviceContainer, rpcContainerList), req, resp, opts...) + if err != nil { + return nil, err + } + + return resp, nil +} diff --git a/api/rpc/grpc/init.go b/api/rpc/grpc/init.go new file mode 100644 index 0000000..0092d39 --- /dev/null +++ b/api/rpc/grpc/init.go @@ -0,0 +1,4 @@ +package grpc + +// Message represents raw gRPC message. +type Message any diff --git a/api/rpc/message/encoding.go b/api/rpc/message/encoding.go new file mode 100644 index 0000000..d656acd --- /dev/null +++ b/api/rpc/message/encoding.go @@ -0,0 +1,40 @@ +package message + +import ( + "encoding/json" +) + +// GRPCConvertedMessage is an interface +// of the gRPC message that is used +// for Message encoding/decoding. +type GRPCConvertedMessage interface { + UnmarshalProtobuf([]byte) error +} + +// Unmarshal decodes m from its Protobuf binary representation +// via related gRPC message. +// +// gm should be tof the same type as the m.ToGRPCMessage() return. +func Unmarshal(m Message, data []byte, gm GRPCConvertedMessage) error { + if err := gm.UnmarshalProtobuf(data); err != nil { + return err + } + + return m.FromGRPCMessage(gm) +} + +// MarshalJSON encodes m to Protobuf JSON representation. +func MarshalJSON(m Message) ([]byte, error) { + return json.Marshal(m.ToGRPCMessage()) +} + +// UnmarshalJSON decodes m from its Protobuf JSON representation +// via related gRPC message. +// +// gm should be tof the same type as the m.ToGRPCMessage() return. +func UnmarshalJSON(m Message, data []byte, gm any) error { + if err := json.Unmarshal(data, gm); err != nil { + return err + } + return m.FromGRPCMessage(gm) +} diff --git a/api/rpc/message/message.go b/api/rpc/message/message.go new file mode 100644 index 0000000..793351f --- /dev/null +++ b/api/rpc/message/message.go @@ -0,0 +1,43 @@ +package message + +import ( + "fmt" + + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/grpc" +) + +// Message represents raw Protobuf message +// that can be transmitted via several +// transport protocols. +type Message interface { + // Must return gRPC message that can + // be used for gRPC protocol transmission. + ToGRPCMessage() grpc.Message + + // Must restore the message from related + // gRPC message. + // + // If gRPC message is not a related one, + // ErrUnexpectedMessageType can be returned + // to indicate this. + FromGRPCMessage(grpc.Message) error +} + +// ErrUnexpectedMessageType is an error that +// is used to indicate message mismatch. +type ErrUnexpectedMessageType struct { + exp, act any +} + +// NewUnexpectedMessageType initializes an error about message mismatch +// between act and exp. +func NewUnexpectedMessageType(act, exp any) ErrUnexpectedMessageType { + return ErrUnexpectedMessageType{ + exp: exp, + act: act, + } +} + +func (e ErrUnexpectedMessageType) Error() string { + return fmt.Sprintf("unexpected message type %T: expected %T", e.act, e.exp) +} diff --git a/api/rpc/message/test/message.go b/api/rpc/message/test/message.go new file mode 100644 index 0000000..a402756 --- /dev/null +++ b/api/rpc/message/test/message.go @@ -0,0 +1,126 @@ +package messagetest + +import ( + "encoding/json" + "errors" + "fmt" + "testing" + + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/util/proto/encoding" + "github.com/stretchr/testify/require" +) + +type jsonMessage interface { + json.Marshaler + json.Unmarshaler +} + +type binaryMessage interface { + StableMarshal([]byte) []byte + StableSize() int + Unmarshal([]byte) error +} + +func TestRPCMessage(t *testing.T, msgGens ...func(empty bool) message.Message) { + for _, msgGen := range msgGens { + msg := msgGen(false) + + t.Run(fmt.Sprintf("convert_%T", msg), func(t *testing.T) { + msg := msgGen(false) + + err := msg.FromGRPCMessage(100) + + require.True(t, errors.As(err, new(message.ErrUnexpectedMessageType))) + + msg2 := msgGen(true) + + err = msg2.FromGRPCMessage(msg.ToGRPCMessage()) + require.NoError(t, err) + + require.Equal(t, msg, msg2) + }) + + t.Run("encoding", func(t *testing.T) { + if jm, ok := msg.(jsonMessage); ok { + t.Run(fmt.Sprintf("JSON_%T", msg), func(t *testing.T) { + data, err := jm.MarshalJSON() + require.NoError(t, err) + + jm2 := msgGen(true).(jsonMessage) + require.NoError(t, jm2.UnmarshalJSON(data)) + + require.Equal(t, jm, jm2) + }) + } + + if bm, ok := msg.(binaryMessage); ok { + t.Run(fmt.Sprintf("%T.StableSize() does no allocations", bm), func(t *testing.T) { + require.Zero(t, testing.AllocsPerRun(1000, func() { + _ = bm.StableSize() + })) + }) + t.Run(fmt.Sprintf("Binary_%T", msg), func(t *testing.T) { + data := bm.StableMarshal(nil) + + bm2 := msgGen(true).(binaryMessage) + require.NoError(t, bm2.Unmarshal(data)) + + require.Equal(t, bm, bm2) + }) + } + t.Run("compatibility", func(t *testing.T) { + testCompatibility(t, msgGen) + }) + }) + } +} + +func testCompatibility(t *testing.T, msgGen func(empty bool) message.Message) { + compareBinary := func(t *testing.T, msg message.Message) { + am, ok := msg.(binaryMessage) + if !ok { + t.Skip() + } + + a := am.StableMarshal(nil) + b := msg.ToGRPCMessage().(encoding.ProtoMarshaler).MarshalProtobuf(nil) + if len(a) == 0 { + require.Empty(t, b) + } else { + require.Equal(t, a, b) + } + } + compareJSON := func(t *testing.T, msg message.Message) { + am, ok := msg.(jsonMessage) + if !ok { + t.Skip() + } + + a, err := am.MarshalJSON() + require.NoError(t, err) + + b, err := json.Marshal(msg.ToGRPCMessage()) + require.NoError(t, err) + + require.JSONEq(t, string(a), string(b)) + } + t.Run("empty", func(t *testing.T) { + msg := msgGen(true) + t.Run(fmt.Sprintf("Binary_%T", msg), func(t *testing.T) { + compareBinary(t, msg) + }) + t.Run(fmt.Sprintf("JSON_%T", msg), func(t *testing.T) { + compareJSON(t, msg) + }) + }) + t.Run("not empty", func(t *testing.T) { + msg := msgGen(false) + t.Run(fmt.Sprintf("Binary_%T", msg), func(t *testing.T) { + compareBinary(t, msg) + }) + t.Run(fmt.Sprintf("JSON_%T", msg), func(t *testing.T) { + compareJSON(t, msg) + }) + }) +} diff --git a/api/rpc/netmap.go b/api/rpc/netmap.go new file mode 100644 index 0000000..fe52b2e --- /dev/null +++ b/api/rpc/netmap.go @@ -0,0 +1,62 @@ +package rpc + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/netmap" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/common" +) + +const serviceNetmap = serviceNamePrefix + "netmap.NetmapService" + +const ( + rpcNetmapNodeInfo = "LocalNodeInfo" + rpcNetmapNetInfo = "NetworkInfo" + rpcNetmapSnapshot = "NetmapSnapshot" +) + +// LocalNodeInfo executes NetmapService.LocalNodeInfo RPC. +func LocalNodeInfo( + cli *client.Client, + req *netmap.LocalNodeInfoRequest, + opts ...client.CallOption, +) (*netmap.LocalNodeInfoResponse, error) { + resp := new(netmap.LocalNodeInfoResponse) + + err := client.SendUnary(cli, common.CallMethodInfoUnary(serviceNetmap, rpcNetmapNodeInfo), req, resp, opts...) + if err != nil { + return nil, err + } + + return resp, nil +} + +// NetworkInfo executes NetmapService.NetworkInfo RPC. +func NetworkInfo( + cli *client.Client, + req *netmap.NetworkInfoRequest, + opts ...client.CallOption, +) (*netmap.NetworkInfoResponse, error) { + resp := new(netmap.NetworkInfoResponse) + err := client.SendUnary(cli, common.CallMethodInfoUnary(serviceNetmap, rpcNetmapNetInfo), req, resp, opts...) + if err != nil { + return nil, err + } + + return resp, nil +} + +// NetMapSnapshot executes NetmapService.NetmapSnapshot RPC. +func NetMapSnapshot( + cli *client.Client, + req *netmap.SnapshotRequest, + opts ...client.CallOption, +) (*netmap.SnapshotResponse, error) { + resp := new(netmap.SnapshotResponse) + + err := client.SendUnary(cli, common.CallMethodInfoUnary(serviceNetmap, rpcNetmapSnapshot), req, resp, opts...) + if err != nil { + return nil, err + } + + return resp, nil +} diff --git a/api/rpc/object.go b/api/rpc/object.go new file mode 100644 index 0000000..b6792f0 --- /dev/null +++ b/api/rpc/object.go @@ -0,0 +1,243 @@ +package rpc + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/common" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" +) + +const serviceObject = serviceNamePrefix + "object.ObjectService" + +const ( + rpcObjectPut = "Put" + rpcObjectGet = "Get" + rpcObjectSearch = "Search" + rpcObjectRange = "GetRange" + rpcObjectHash = "GetRangeHash" + rpcObjectHead = "Head" + rpcObjectDelete = "Delete" + rpcObjectPutSingle = "PutSingle" + rpcObjectPatch = "Patch" +) + +// PutRequestWriter is an object.PutRequest +// message streaming component. +type PutRequestWriter struct { + wc client.MessageWriterCloser + + resp message.Message +} + +// Write writes req to the stream. +func (w *PutRequestWriter) Write(req *object.PutRequest) error { + return w.wc.WriteMessage(req) +} + +// Close closes the stream. +func (w *PutRequestWriter) Close() error { + return w.wc.Close() +} + +// PutObject executes ObjectService.Put RPC. +func PutObject( + cli *client.Client, + resp *object.PutResponse, + opts ...client.CallOption, +) (*PutRequestWriter, error) { + wc, err := client.OpenClientStream(cli, common.CallMethodInfoClientStream(serviceObject, rpcObjectPut), resp, opts...) + if err != nil { + return nil, err + } + + return &PutRequestWriter{ + wc: wc, + resp: resp, + }, nil +} + +// GetResponseReader is an object.GetResponse +// stream reader. +type GetResponseReader struct { + r client.MessageReader +} + +// Read reads response from the stream. +// +// Returns io.EOF of streaming is finished. +func (r *GetResponseReader) Read(resp *object.GetResponse) error { + return r.r.ReadMessage(resp) +} + +// GetObject executes ObjectService.Get RPC. +func GetObject( + cli *client.Client, + req *object.GetRequest, + opts ...client.CallOption, +) (*GetResponseReader, error) { + wc, err := client.OpenServerStream(cli, common.CallMethodInfoServerStream(serviceObject, rpcObjectGet), req, opts...) + if err != nil { + return nil, err + } + + return &GetResponseReader{ + r: wc, + }, nil +} + +// GetResponseReader is an object.SearchResponse +// stream reader. +type SearchResponseReader struct { + r client.MessageReader +} + +// Read reads response from the stream. +// +// Returns io.EOF of streaming is finished. +func (r *SearchResponseReader) Read(resp *object.SearchResponse) error { + return r.r.ReadMessage(resp) +} + +// SearchObjects executes ObjectService.Search RPC. +func SearchObjects( + cli *client.Client, + req *object.SearchRequest, + opts ...client.CallOption, +) (*SearchResponseReader, error) { + wc, err := client.OpenServerStream(cli, common.CallMethodInfoServerStream(serviceObject, rpcObjectSearch), req, opts...) + if err != nil { + return nil, err + } + + return &SearchResponseReader{ + r: wc, + }, nil +} + +// GetResponseReader is an object.GetRangeResponse +// stream reader. +type ObjectRangeResponseReader struct { + r client.MessageReader +} + +// Read reads response from the stream. +// +// Returns io.EOF of streaming is finished. +func (r *ObjectRangeResponseReader) Read(resp *object.GetRangeResponse) error { + return r.r.ReadMessage(resp) +} + +// GetObjectRange executes ObjectService.GetRange RPC. +func GetObjectRange( + cli *client.Client, + req *object.GetRangeRequest, + opts ...client.CallOption, +) (*ObjectRangeResponseReader, error) { + wc, err := client.OpenServerStream(cli, common.CallMethodInfoServerStream(serviceObject, rpcObjectRange), req, opts...) + if err != nil { + return nil, err + } + + return &ObjectRangeResponseReader{ + r: wc, + }, nil +} + +// HeadObject executes ObjectService.Head RPC. +func HeadObject( + cli *client.Client, + req *object.HeadRequest, + opts ...client.CallOption, +) (*object.HeadResponse, error) { + resp := new(object.HeadResponse) + + err := client.SendUnary(cli, common.CallMethodInfoUnary(serviceObject, rpcObjectHead), req, resp, opts...) + if err != nil { + return nil, err + } + + return resp, nil +} + +// DeleteObject executes ObjectService.Delete RPC. +func DeleteObject( + cli *client.Client, + req *object.DeleteRequest, + opts ...client.CallOption, +) (*object.DeleteResponse, error) { + resp := new(object.DeleteResponse) + + err := client.SendUnary(cli, common.CallMethodInfoUnary(serviceObject, rpcObjectDelete), req, resp, opts...) + if err != nil { + return nil, err + } + + return resp, nil +} + +// HashObjectRange executes ObjectService.GetRangeHash RPC. +func HashObjectRange( + cli *client.Client, + req *object.GetRangeHashRequest, + opts ...client.CallOption, +) (*object.GetRangeHashResponse, error) { + resp := new(object.GetRangeHashResponse) + + err := client.SendUnary(cli, common.CallMethodInfoUnary(serviceObject, rpcObjectHash), req, resp, opts...) + if err != nil { + return nil, err + } + + return resp, nil +} + +// PutSingleObject executes ObjectService.PutSingle RPC. +func PutSingleObject( + cli *client.Client, + req *object.PutSingleRequest, + opts ...client.CallOption, +) (*object.PutSingleResponse, error) { + resp := new(object.PutSingleResponse) + + err := client.SendUnary(cli, common.CallMethodInfoUnary(serviceObject, rpcObjectPutSingle), req, resp, opts...) + if err != nil { + return nil, err + } + + return resp, nil +} + +// PatchRequestWriter is an object.PatchRequest +// message streaming component. +type PatchRequestWriter struct { + wc client.MessageWriterCloser + + resp message.Message +} + +// Write writes req to the stream. +func (w *PatchRequestWriter) Write(req *object.PatchRequest) error { + return w.wc.WriteMessage(req) +} + +// Close closes the stream. +func (w *PatchRequestWriter) Close() error { + return w.wc.Close() +} + +// Patch executes ObjectService.Patch RPC. +func Patch( + cli *client.Client, + resp *object.PatchResponse, + opts ...client.CallOption, +) (*PatchRequestWriter, error) { + wc, err := client.OpenClientStream(cli, common.CallMethodInfoClientStream(serviceObject, rpcObjectPatch), resp, opts...) + if err != nil { + return nil, err + } + + return &PatchRequestWriter{ + wc: wc, + resp: resp, + }, nil +} diff --git a/api/rpc/session.go b/api/rpc/session.go new file mode 100644 index 0000000..2477029 --- /dev/null +++ b/api/rpc/session.go @@ -0,0 +1,28 @@ +package rpc + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/common" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" +) + +const serviceSession = serviceNamePrefix + "session.SessionService" + +const ( + rpcSessionCreate = "Create" +) + +func CreateSession( + cli *client.Client, + req *session.CreateRequest, + opts ...client.CallOption, +) (*session.CreateResponse, error) { + resp := new(session.CreateResponse) + + err := client.SendUnary(cli, common.CallMethodInfoUnary(serviceSession, rpcSessionCreate), req, resp, opts...) + if err != nil { + return nil, err + } + + return resp, nil +} diff --git a/api/session/convert.go b/api/session/convert.go new file mode 100644 index 0000000..342be4e --- /dev/null +++ b/api/session/convert.go @@ -0,0 +1,898 @@ +package session + +import ( + "fmt" + + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" + aclGRPC "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + refsGRPC "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status" + statusGRPC "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status/grpc" +) + +func (c *CreateRequestBody) ToGRPCMessage() grpc.Message { + var m *session.CreateRequest_Body + + if c != nil { + m = new(session.CreateRequest_Body) + + m.SetOwnerId(c.ownerID.ToGRPCMessage().(*refsGRPC.OwnerID)) + m.SetExpiration(c.expiration) + } + + return m +} + +func (c *CreateRequestBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*session.CreateRequest_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + ownerID := v.GetOwnerId() + if ownerID == nil { + c.ownerID = nil + } else { + if c.ownerID == nil { + c.ownerID = new(refs.OwnerID) + } + + err = c.ownerID.FromGRPCMessage(ownerID) + if err != nil { + return err + } + } + + c.expiration = v.GetExpiration() + + return nil +} + +func (c *CreateRequest) ToGRPCMessage() grpc.Message { + var m *session.CreateRequest + + if c != nil { + m = new(session.CreateRequest) + + m.SetBody(c.body.ToGRPCMessage().(*session.CreateRequest_Body)) + c.RequestHeaders.ToMessage(m) + } + + return m +} + +func (c *CreateRequest) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*session.CreateRequest) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + c.body = nil + } else { + if c.body == nil { + c.body = new(CreateRequestBody) + } + + err = c.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + return c.RequestHeaders.FromMessage(v) +} + +func (c *CreateResponseBody) ToGRPCMessage() grpc.Message { + var m *session.CreateResponse_Body + + if c != nil { + m = new(session.CreateResponse_Body) + + m.SetSessionKey(c.sessionKey) + m.SetId(c.id) + } + + return m +} + +func (c *CreateResponseBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*session.CreateResponse_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + c.sessionKey = v.GetSessionKey() + c.id = v.GetId() + + return nil +} + +func (c *CreateResponse) ToGRPCMessage() grpc.Message { + var m *session.CreateResponse + + if c != nil { + m = new(session.CreateResponse) + + m.SetBody(c.body.ToGRPCMessage().(*session.CreateResponse_Body)) + c.ResponseHeaders.ToMessage(m) + } + + return m +} + +func (c *CreateResponse) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*session.CreateResponse) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + c.body = nil + } else { + if c.body == nil { + c.body = new(CreateResponseBody) + } + + err = c.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + return c.ResponseHeaders.FromMessage(v) +} + +func (l *TokenLifetime) ToGRPCMessage() grpc.Message { + var m *session.SessionToken_Body_TokenLifetime + + if l != nil { + m = new(session.SessionToken_Body_TokenLifetime) + + m.SetExp(l.exp) + m.SetIat(l.iat) + m.SetNbf(l.nbf) + } + + return m +} + +func (l *TokenLifetime) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*session.SessionToken_Body_TokenLifetime) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + l.exp = v.GetExp() + l.iat = v.GetIat() + l.nbf = v.GetNbf() + + return nil +} + +func (x *XHeader) ToGRPCMessage() grpc.Message { + var m *session.XHeader + + if x != nil { + m = new(session.XHeader) + + m.SetKey(x.key) + m.SetValue(x.val) + } + + return m +} + +func (x *XHeader) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*session.XHeader) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + x.key = v.GetKey() + x.val = v.GetValue() + + return nil +} + +func XHeadersToGRPC(xs []XHeader) (res []session.XHeader) { + if xs != nil { + res = make([]session.XHeader, 0, len(xs)) + + for i := range xs { + res = append(res, *xs[i].ToGRPCMessage().(*session.XHeader)) + } + } + + return +} + +func XHeadersFromGRPC(xs []session.XHeader) (res []XHeader, err error) { + if xs != nil { + res = make([]XHeader, len(xs)) + + for i := range xs { + err = res[i].FromGRPCMessage(&xs[i]) + if err != nil { + return + } + } + } + + return +} + +func (t *Token) ToGRPCMessage() grpc.Message { + var m *session.SessionToken + + if t != nil { + m = new(session.SessionToken) + + m.SetBody(t.body.ToGRPCMessage().(*session.SessionToken_Body)) + m.SetSignature(t.sig.ToGRPCMessage().(*refsGRPC.Signature)) + } + + return m +} + +func (t *Token) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*session.SessionToken) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + body := v.GetBody() + if body == nil { + t.body = nil + } else { + if t.body == nil { + t.body = new(TokenBody) + } + + err = t.body.FromGRPCMessage(body) + if err != nil { + return err + } + } + + sig := v.GetSignature() + if sig == nil { + t.sig = nil + } else { + if t.sig == nil { + t.sig = new(refs.Signature) + } + + err = t.sig.FromGRPCMessage(sig) + if err != nil { + return err + } + } + + return nil +} + +func (r *RequestVerificationHeader) ToGRPCMessage() grpc.Message { + var m *session.RequestVerificationHeader + + if r != nil { + m = new(session.RequestVerificationHeader) + + m.SetBodySignature(r.bodySig.ToGRPCMessage().(*refsGRPC.Signature)) + m.SetMetaSignature(r.metaSig.ToGRPCMessage().(*refsGRPC.Signature)) + m.SetOriginSignature(r.originSig.ToGRPCMessage().(*refsGRPC.Signature)) + m.SetOrigin(r.origin.ToGRPCMessage().(*session.RequestVerificationHeader)) + } + + return m +} + +func (r *RequestVerificationHeader) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*session.RequestVerificationHeader) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + originSig := v.GetOriginSignature() + if originSig == nil { + r.originSig = nil + } else { + if r.originSig == nil { + r.originSig = new(refs.Signature) + } + + err = r.originSig.FromGRPCMessage(originSig) + if err != nil { + return err + } + } + + metaSig := v.GetMetaSignature() + if metaSig == nil { + r.metaSig = nil + } else { + if r.metaSig == nil { + r.metaSig = new(refs.Signature) + } + + err = r.metaSig.FromGRPCMessage(metaSig) + if err != nil { + return err + } + } + + bodySig := v.GetBodySignature() + if bodySig == nil { + r.bodySig = nil + } else { + if r.bodySig == nil { + r.bodySig = new(refs.Signature) + } + + err = r.bodySig.FromGRPCMessage(bodySig) + if err != nil { + return err + } + } + + origin := v.GetOrigin() + if origin == nil { + r.origin = nil + } else { + if r.origin == nil { + r.origin = new(RequestVerificationHeader) + } + + err = r.origin.FromGRPCMessage(origin) + if err != nil { + return err + } + } + + return nil +} + +func (r *RequestMetaHeader) ToGRPCMessage() grpc.Message { + var m *session.RequestMetaHeader + + if r != nil { + m = new(session.RequestMetaHeader) + + m.SetVersion(r.version.ToGRPCMessage().(*refsGRPC.Version)) + m.SetSessionToken(r.sessionToken.ToGRPCMessage().(*session.SessionToken)) + m.SetBearerToken(r.bearerToken.ToGRPCMessage().(*aclGRPC.BearerToken)) + m.SetXHeaders(XHeadersToGRPC(r.xHeaders)) + m.SetEpoch(r.epoch) + m.SetTtl(r.ttl) + m.SetOrigin(r.origin.ToGRPCMessage().(*session.RequestMetaHeader)) + m.SetMagicNumber(r.netMagic) + } + + return m +} + +func (r *RequestMetaHeader) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*session.RequestMetaHeader) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + version := v.GetVersion() + if version == nil { + r.version = nil + } else { + if r.version == nil { + r.version = new(refs.Version) + } + + err = r.version.FromGRPCMessage(version) + if err != nil { + return err + } + } + + sessionToken := v.GetSessionToken() + if sessionToken == nil { + r.sessionToken = nil + } else { + if r.sessionToken == nil { + r.sessionToken = new(Token) + } + + err = r.sessionToken.FromGRPCMessage(sessionToken) + if err != nil { + return err + } + } + + bearerToken := v.GetBearerToken() + if bearerToken == nil { + r.bearerToken = nil + } else { + if r.bearerToken == nil { + r.bearerToken = new(acl.BearerToken) + } + + err = r.bearerToken.FromGRPCMessage(bearerToken) + if err != nil { + return err + } + } + + origin := v.GetOrigin() + if origin == nil { + r.origin = nil + } else { + if r.origin == nil { + r.origin = new(RequestMetaHeader) + } + + err = r.origin.FromGRPCMessage(origin) + if err != nil { + return err + } + } + + r.xHeaders, err = XHeadersFromGRPC(v.GetXHeaders()) + if err != nil { + return err + } + + r.epoch = v.GetEpoch() + r.ttl = v.GetTtl() + r.netMagic = v.GetMagicNumber() + + return nil +} + +func (r *ResponseVerificationHeader) ToGRPCMessage() grpc.Message { + var m *session.ResponseVerificationHeader + + if r != nil { + m = new(session.ResponseVerificationHeader) + + m.SetBodySignature(r.bodySig.ToGRPCMessage().(*refsGRPC.Signature)) + m.SetMetaSignature(r.metaSig.ToGRPCMessage().(*refsGRPC.Signature)) + m.SetOriginSignature(r.originSig.ToGRPCMessage().(*refsGRPC.Signature)) + m.SetOrigin(r.origin.ToGRPCMessage().(*session.ResponseVerificationHeader)) + } + + return m +} + +func (r *ResponseVerificationHeader) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*session.ResponseVerificationHeader) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + originSig := v.GetOriginSignature() + if originSig == nil { + r.originSig = nil + } else { + if r.originSig == nil { + r.originSig = new(refs.Signature) + } + + err = r.originSig.FromGRPCMessage(originSig) + if err != nil { + return err + } + } + + metaSig := v.GetMetaSignature() + if metaSig == nil { + r.metaSig = nil + } else { + if r.metaSig == nil { + r.metaSig = new(refs.Signature) + } + + err = r.metaSig.FromGRPCMessage(metaSig) + if err != nil { + return err + } + } + + bodySig := v.GetBodySignature() + if bodySig == nil { + r.bodySig = nil + } else { + if r.bodySig == nil { + r.bodySig = new(refs.Signature) + } + + err = r.bodySig.FromGRPCMessage(bodySig) + if err != nil { + return err + } + } + + origin := v.GetOrigin() + if origin == nil { + r.origin = nil + } else { + if r.origin == nil { + r.origin = new(ResponseVerificationHeader) + } + + err = r.origin.FromGRPCMessage(origin) + if err != nil { + return err + } + } + + return nil +} + +func (r *ResponseMetaHeader) ToGRPCMessage() grpc.Message { + var m *session.ResponseMetaHeader + + if r != nil { + m = new(session.ResponseMetaHeader) + + m.SetVersion(r.version.ToGRPCMessage().(*refsGRPC.Version)) + m.SetXHeaders(XHeadersToGRPC(r.xHeaders)) + m.SetEpoch(r.epoch) + m.SetTtl(r.ttl) + m.SetOrigin(r.origin.ToGRPCMessage().(*session.ResponseMetaHeader)) + m.SetStatus(r.status.ToGRPCMessage().(*statusGRPC.Status)) + } + + return m +} + +func (r *ResponseMetaHeader) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*session.ResponseMetaHeader) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + version := v.GetVersion() + if version == nil { + r.version = nil + } else { + if r.version == nil { + r.version = new(refs.Version) + } + + err = r.version.FromGRPCMessage(version) + if err != nil { + return err + } + } + + origin := v.GetOrigin() + if origin == nil { + r.origin = nil + } else { + if r.origin == nil { + r.origin = new(ResponseMetaHeader) + } + + err = r.origin.FromGRPCMessage(origin) + if err != nil { + return err + } + } + + st := v.GetStatus() + if st == nil { + r.status = nil + } else { + if r.status == nil { + r.status = new(status.Status) + } + + err = r.status.FromGRPCMessage(st) + if err != nil { + return err + } + } + + r.xHeaders, err = XHeadersFromGRPC(v.GetXHeaders()) + if err != nil { + return err + } + + r.epoch = v.GetEpoch() + r.ttl = v.GetTtl() + + return nil +} + +func ObjectSessionVerbToGRPCField(v ObjectSessionVerb) session.ObjectSessionContext_Verb { + switch v { + case ObjectVerbPut: + return session.ObjectSessionContext_PUT + case ObjectVerbGet: + return session.ObjectSessionContext_GET + case ObjectVerbHead: + return session.ObjectSessionContext_HEAD + case ObjectVerbSearch: + return session.ObjectSessionContext_SEARCH + case ObjectVerbDelete: + return session.ObjectSessionContext_DELETE + case ObjectVerbRange: + return session.ObjectSessionContext_RANGE + case ObjectVerbRangeHash: + return session.ObjectSessionContext_RANGEHASH + case ObjectVerbPatch: + return session.ObjectSessionContext_PATCH + default: + return session.ObjectSessionContext_VERB_UNSPECIFIED + } +} + +func ObjectSessionVerbFromGRPCField(v session.ObjectSessionContext_Verb) ObjectSessionVerb { + switch v { + case session.ObjectSessionContext_PUT: + return ObjectVerbPut + case session.ObjectSessionContext_GET: + return ObjectVerbGet + case session.ObjectSessionContext_HEAD: + return ObjectVerbHead + case session.ObjectSessionContext_SEARCH: + return ObjectVerbSearch + case session.ObjectSessionContext_DELETE: + return ObjectVerbDelete + case session.ObjectSessionContext_RANGE: + return ObjectVerbRange + case session.ObjectSessionContext_RANGEHASH: + return ObjectVerbRangeHash + case session.ObjectSessionContext_PATCH: + return ObjectVerbPatch + default: + return ObjectVerbUnknown + } +} + +func (c *ObjectSessionContext) ToGRPCMessage() grpc.Message { + var m *session.ObjectSessionContext + + if c != nil { + m = new(session.ObjectSessionContext) + + m.SetVerb(ObjectSessionVerbToGRPCField(c.verb)) + m.SetTarget(&session.ObjectSessionContext_Target{ + Container: c.cnr.ToGRPCMessage().(*refsGRPC.ContainerID), + Objects: refs.ObjectIDListToGRPCMessage(c.objs), + }) + } + + return m +} + +func (c *ObjectSessionContext) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*session.ObjectSessionContext) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + cnr := v.GetTarget().GetContainer() + if cnr == nil { + c.cnr = nil + } else { + if c.cnr == nil { + c.cnr = new(refs.ContainerID) + } + + err = c.cnr.FromGRPCMessage(cnr) + if err != nil { + return err + } + } + + c.objs, err = refs.ObjectIDListFromGRPCMessage(v.GetTarget().GetObjects()) + if err != nil { + return err + } + + c.verb = ObjectSessionVerbFromGRPCField(v.GetVerb()) + + return nil +} + +func (t *TokenBody) ToGRPCMessage() grpc.Message { + var m *session.SessionToken_Body + + if t != nil { + m = new(session.SessionToken_Body) + + switch typ := t.ctx.(type) { + default: + panic(fmt.Sprintf("unknown session context %T", typ)) + case nil: + m.Context = nil + case *ObjectSessionContext: + m.SetObject(typ.ToGRPCMessage().(*session.ObjectSessionContext)) + case *ContainerSessionContext: + m.SetContainer(typ.ToGRPCMessage().(*session.ContainerSessionContext)) + } + + m.SetOwnerId(t.ownerID.ToGRPCMessage().(*refsGRPC.OwnerID)) + m.SetId(t.id) + m.SetSessionKey(t.sessionKey) + m.SetLifetime(t.lifetime.ToGRPCMessage().(*session.SessionToken_Body_TokenLifetime)) + } + + return m +} + +func (t *TokenBody) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*session.SessionToken_Body) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + t.ctx = nil + + switch val := v.GetContext().(type) { + default: + err = fmt.Errorf("unknown session context %T", val) + case nil: + case *session.SessionToken_Body_Object: + ctx, ok := t.ctx.(*ObjectSessionContext) + if !ok { + ctx = new(ObjectSessionContext) + t.ctx = ctx + } + + err = ctx.FromGRPCMessage(val.Object) + case *session.SessionToken_Body_Container: + ctx, ok := t.ctx.(*ContainerSessionContext) + if !ok { + ctx = new(ContainerSessionContext) + t.ctx = ctx + } + + err = ctx.FromGRPCMessage(val.Container) + } + + if err != nil { + return err + } + + ownerID := v.GetOwnerId() + if ownerID == nil { + t.ownerID = nil + } else { + if t.ownerID == nil { + t.ownerID = new(refs.OwnerID) + } + + err = t.ownerID.FromGRPCMessage(ownerID) + if err != nil { + return err + } + } + + lifetime := v.GetLifetime() + if lifetime == nil { + t.lifetime = nil + } else { + if t.lifetime == nil { + t.lifetime = new(TokenLifetime) + } + + err = t.lifetime.FromGRPCMessage(lifetime) + if err != nil { + return err + } + } + + t.id = v.GetId() + t.sessionKey = v.GetSessionKey() + + return nil +} + +// ContainerSessionVerbToGRPCField converts ContainerSessionVerb +// to gRPC-generated session.ContainerSessionContext_Verb. +// +// If v is outside of the ContainerSessionVerb enum, +// session.ContainerSessionContext_VERB_UNSPECIFIED is returned. +func ContainerSessionVerbToGRPCField(v ContainerSessionVerb) session.ContainerSessionContext_Verb { + switch v { + default: + return session.ContainerSessionContext_VERB_UNSPECIFIED + case ContainerVerbPut: + return session.ContainerSessionContext_PUT + case ContainerVerbDelete: + return session.ContainerSessionContext_DELETE + case ContainerVerbSetEACL: + return session.ContainerSessionContext_SETEACL + } +} + +// ContainerSessionVerbFromGRPCField converts gRPC-generated +// session.ContainerSessionContext_Verb to ContainerSessionVerb. +// +// If v is outside of the session.ContainerSessionContext_Verb enum, +// ContainerVerbUnknown is returned. +func ContainerSessionVerbFromGRPCField(v session.ContainerSessionContext_Verb) ContainerSessionVerb { + switch v { + default: + return ContainerVerbUnknown + case session.ContainerSessionContext_PUT: + return ContainerVerbPut + case session.ContainerSessionContext_DELETE: + return ContainerVerbDelete + case session.ContainerSessionContext_SETEACL: + return ContainerVerbSetEACL + } +} + +// ToGRPCMessage converts ContainerSessionContext to gRPC-generated +// session.ContainerSessionContext message. +func (x *ContainerSessionContext) ToGRPCMessage() grpc.Message { + var m *session.ContainerSessionContext + + if x != nil { + m = new(session.ContainerSessionContext) + + m.SetVerb(ContainerSessionVerbToGRPCField(x.verb)) + m.SetWildcard(x.wildcard) + m.SetContainerId(x.cid.ToGRPCMessage().(*refsGRPC.ContainerID)) + } + + return m +} + +// FromGRPCMessage tries to restore ContainerSessionContext from grpc.Message. +// +// Returns message.ErrUnexpectedMessageType if m is not +// a gRPC-generated session.ContainerSessionContext message. +func (x *ContainerSessionContext) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*session.ContainerSessionContext) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var err error + + cid := v.GetContainerId() + if cid == nil { + x.cid = nil + } else { + if x.cid == nil { + x.cid = new(refs.ContainerID) + } + + err = x.cid.FromGRPCMessage(cid) + if err != nil { + return err + } + } + + x.verb = ContainerSessionVerbFromGRPCField(v.GetVerb()) + x.wildcard = v.GetWildcard() + + return nil +} diff --git a/api/session/grpc/service_frostfs.pb.go b/api/session/grpc/service_frostfs.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..1c8e02b6d1c3f3a3ff133df4b089f805bbfd72b3 GIT binary patch literal 20352 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 literal 0 HcmV?d00001 diff --git a/api/session/grpc/service_frostfs_fuzz.go b/api/session/grpc/service_frostfs_fuzz.go new file mode 100644 index 0000000..759361c --- /dev/null +++ b/api/session/grpc/service_frostfs_fuzz.go @@ -0,0 +1,45 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package session + +func DoFuzzProtoCreateRequest(data []byte) int { + msg := new(CreateRequest) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONCreateRequest(data []byte) int { + msg := new(CreateRequest) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} +func DoFuzzProtoCreateResponse(data []byte) int { + msg := new(CreateResponse) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONCreateResponse(data []byte) int { + msg := new(CreateResponse) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} diff --git a/api/session/grpc/service_frostfs_test.go b/api/session/grpc/service_frostfs_test.go new file mode 100644 index 0000000..fc8664e --- /dev/null +++ b/api/session/grpc/service_frostfs_test.go @@ -0,0 +1,31 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package session + +import ( + testing "testing" +) + +func FuzzProtoCreateRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoCreateRequest(data) + }) +} +func FuzzJSONCreateRequest(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONCreateRequest(data) + }) +} +func FuzzProtoCreateResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoCreateResponse(data) + }) +} +func FuzzJSONCreateResponse(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONCreateResponse(data) + }) +} diff --git a/api/session/grpc/service_grpc.pb.go b/api/session/grpc/service_grpc.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..6073111a36083bca0fdbec0a4541e419db3ab6aa GIT binary patch literal 4116 zcmds4U2oeq6n&0<#hnLqa^TQehM|CqU?|*lGq%P>oa|*70!E^2p|YrwlwG69f8V*J zWLt@o6a)6MAPH>o@_w9izcd`uSf`5Ss#HcgmD1gYDx;lFPVnqxu21HsN(8-|(&hA; zF5XS9MKm1JN*SB$(vJAc$$=}h`ceEOPWO*#|7Z2HID0M5_}uE+Bx*#m%7<22);naY z_+nOhqJ(!SiYl3Wl5<6kOcdqIN*hOUbd>1QsV|Ot&4*re#2TnK*Lq$kG1rAG=R%vg z*No!?VcVz9hyD~&)=5`CEf$V@Q9t51t{1r_{7OpnvdRl};_{^;X%UA*P~P{i@H5af=_JbDbMR zIKTQhKKWI9I?lu?X+s5wHX;I4*3m7Ud(~oASB&Pz0P@8C85n*YHG)8S7RZ?eT5iWi zLDTK~x+p#lX}7pg6I;LnA&z-*|>l%cZ@AuRb5P_hH63MC(R~y!Z2WIhu)z>C)`?>PlO!bbj)h5!FRRGvG9jj=lgL3he&%lf zFn2I$l&eiiuMYY3HA(KbR^x<@4+-_@zs8Pn(Y2$|IcHVeQV{^|M@K-I&k~U&Vp6X3 zC&fG>fjS@^u6AY@bk+^0pcD%8j9H`aU@tG&dW#aidP1Y4`z><*E)Ezdq;S_L(~L?) ztK(L{#g1<;w*q=w6olbWs3kfH8YxnV>_XQ?N@{tBDR)zDk5zieCi}wu27ha5&^Vfo zoEN#<94hD5)i&M!7v&sEcvs5X>hyK|e7OR^7g26Wxl@6c6x49rl`HiKdCbBsXMxhD zt$u@*wm-BjAb#=At}Op82Alv*ckp>1b_H?4{Va?9f+0F?45+vCW3=fARBBAYHj7o- z^Ig!xYGtMlWi2h`25r3qCVDLwDCz7Gq&}H_n)_9R>xct8hVDTzEKI!bay0{rAZnx;kTt7=VfC43D|Sl##rRcM`)#A} zowAA7wQ~nYe&uZ>+CKXm)|En;nC)(3{(3*~>&&AWo2rC3xOh*rA28(>jc5~9IrK9h z-AyUYhV3ac*`1-B_ine7m%{^94~9pm|81+sDLlaS{+n-U{TLAYKAk@r6bM?xU0i~@ zeX*OC92lkzMoC^~nmv5=IJ!*3e=M#X>&U-$0Q`V{{oB9Ec(o6TWx!p5w{z|-=pJZb&|$Q# za20xxwo9GnS&q-KTJe4yUb3o9KU&F$F9n@w+LxP9&m0Kyp(!<{bws_FURHXbzNyA* ztnni(sa+hJ)Qr*Q`;ZOqLUu%d{q3U--y73MoQ{o1V?SgxTRCd&_)LAiF|hbO{_$UU c%Yen!WO(3B@;N+^sdN&-KL3slC+?$v0Q;Mfv;Y7A literal 0 HcmV?d00001 diff --git a/api/session/grpc/types_frostfs.pb.go b/api/session/grpc/types_frostfs.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..c62c1ffb5821f2e1f61463dc1cdb9adde06d5e66 GIT binary patch literal 70892 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 0 { + ds = make([]status.Status_Detail, 0, ln) + + for i := range ln { + ds = append(ds, *x.details[i].ToGRPCMessage().(*status.Status_Detail)) + } + } + + m.SetDetails(ds) + } + + return m +} + +func (x *Status) FromGRPCMessage(m grpc.Message) error { + v, ok := m.(*status.Status) + if !ok { + return message.NewUnexpectedMessageType(m, v) + } + + var ( + ds []Detail + dsV2 = v.GetDetails() + ) + + if dsV2 != nil { + ln := len(dsV2) + + ds = make([]Detail, ln) + + for i := range ln { + if err := ds[i].FromGRPCMessage(&dsV2[i]); err != nil { + return err + } + } + } + + x.details = ds + x.msg = v.GetMessage() + x.code = CodeFromGRPC(v.GetCode()) + + return nil +} diff --git a/api/status/details.go b/api/status/details.go new file mode 100644 index 0000000..5b8f460 --- /dev/null +++ b/api/status/details.go @@ -0,0 +1,8 @@ +package status + +// details for WrongMagicNumber code. +const ( + // DetailIDCorrectMagic is an identifier of details with correct network magic + // which can be attached to WrongMagicNumber code. + DetailIDCorrectMagic = iota +) diff --git a/api/status/grpc/types_frostfs.pb.go b/api/status/grpc/types_frostfs.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..35dec1144b59f5908611087980500032a35e6b82 GIT binary patch literal 14223 zcmeHNZF3q&68;RoVoX&M@X26FPCh85tHKDWuqAK_$+;^>MOLs_Yr`(JyCC^o`tSF2 zPtVTm@+KwL<#Kf@+cGmfJnE$xqVO$#q3 zMK*^Fy{WGb)zq7P;5)m*l|r+>mP@6V2dYxIugVU_cb)P4-SG6DGp(vBiO&3mapmuZ9a*AxR+RIJb z(+I_WZrU6vTmC9H?VgNDe#G=WNoqU~hpKvKl&GfqEShQ!eu-qHaKvD&7CS2XtPTzh z-GD@@g;~9;UHwe6bQ!Uq&f`!m`1a%j7?B~>kE3|%rJXRX;_iNWg>^e>_hqeopMiKT z3R6?ZaWoYqi6E(|YjS&Q@UVnFBo@i@J7}Ent1fC5TM94f!W(;�Lnm?fG!%C&{vH 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 literal 0 HcmV?d00001 diff --git a/api/tombstone/grpc/types_frostfs_fuzz.go b/api/tombstone/grpc/types_frostfs_fuzz.go new file mode 100644 index 0000000..57cfb58 --- /dev/null +++ b/api/tombstone/grpc/types_frostfs_fuzz.go @@ -0,0 +1,26 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package tombstone + +func DoFuzzProtoTombstone(data []byte) int { + msg := new(Tombstone) + if err := msg.UnmarshalProtobuf(data); err != nil { + return 0 + } + _ = msg.MarshalProtobuf(nil) + return 1 +} +func DoFuzzJSONTombstone(data []byte) int { + msg := new(Tombstone) + if err := msg.UnmarshalJSON(data); err != nil { + return 0 + } + _, err := msg.MarshalJSON() + if err != nil { + panic(err) + } + return 1 +} diff --git a/api/tombstone/grpc/types_frostfs_test.go b/api/tombstone/grpc/types_frostfs_test.go new file mode 100644 index 0000000..8264824 --- /dev/null +++ b/api/tombstone/grpc/types_frostfs_test.go @@ -0,0 +1,21 @@ +//go:build gofuzz +// +build gofuzz + +// Code generated by protoc-gen-go-frostfs. DO NOT EDIT. + +package tombstone + +import ( + testing "testing" +) + +func FuzzProtoTombstone(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzProtoTombstone(data) + }) +} +func FuzzJSONTombstone(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + DoFuzzJSONTombstone(data) + }) +} diff --git a/api/tombstone/json.go b/api/tombstone/json.go new file mode 100644 index 0000000..9b816fe --- /dev/null +++ b/api/tombstone/json.go @@ -0,0 +1,14 @@ +package tombstone + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + tombstone "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/tombstone/grpc" +) + +func (s *Tombstone) MarshalJSON() ([]byte, error) { + return message.MarshalJSON(s) +} + +func (s *Tombstone) UnmarshalJSON(data []byte) error { + return message.UnmarshalJSON(s, data, new(tombstone.Tombstone)) +} diff --git a/api/tombstone/marshal.go b/api/tombstone/marshal.go new file mode 100644 index 0000000..dda9469 --- /dev/null +++ b/api/tombstone/marshal.go @@ -0,0 +1,56 @@ +package tombstone + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + tombstone "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/tombstone/grpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/util/proto" +) + +const ( + expFNum = 1 + splitIDFNum = 2 + membersFNum = 3 +) + +// StableMarshal marshals unified tombstone message in a protobuf +// compatible way without field order shuffle. +func (s *Tombstone) StableMarshal(buf []byte) []byte { + if s == nil { + return []byte{} + } + + if buf == nil { + buf = make([]byte, s.StableSize()) + } + + var offset int + + offset += proto.UInt64Marshal(expFNum, buf[offset:], s.exp) + offset += proto.BytesMarshal(splitIDFNum, buf[offset:], s.splitID) + + for i := range s.members { + offset += proto.NestedStructureMarshal(membersFNum, buf[offset:], &s.members[i]) + } + + return buf +} + +// StableSize returns size of tombstone message marshalled by StableMarshal function. +func (s *Tombstone) StableSize() (size int) { + if s == nil { + return 0 + } + + size += proto.UInt64Size(expFNum, s.exp) + size += proto.BytesSize(splitIDFNum, s.splitID) + for i := range s.members { + size += proto.NestedStructureSize(membersFNum, &s.members[i]) + } + + return size +} + +// Unmarshal unmarshal tombstone message from its binary representation. +func (s *Tombstone) Unmarshal(data []byte) error { + return message.Unmarshal(s, data, new(tombstone.Tombstone)) +} diff --git a/api/tombstone/message_test.go b/api/tombstone/message_test.go new file mode 100644 index 0000000..dec17cc --- /dev/null +++ b/api/tombstone/message_test.go @@ -0,0 +1,15 @@ +package tombstone_test + +import ( + "testing" + + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message" + messagetest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/message/test" + tombstonetest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/tombstone/test" +) + +func TestMessageConvert(t *testing.T) { + messagetest.TestRPCMessage(t, + func(empty bool) message.Message { return tombstonetest.GenerateTombstone(empty) }, + ) +} diff --git a/api/tombstone/test/generate.go b/api/tombstone/test/generate.go new file mode 100644 index 0000000..c71bd81 --- /dev/null +++ b/api/tombstone/test/generate.go @@ -0,0 +1,23 @@ +package tombstonetest + +import ( + "crypto/rand" + + refstest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs/test" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/tombstone" +) + +func GenerateTombstone(empty bool) *tombstone.Tombstone { + m := new(tombstone.Tombstone) + + if !empty { + id := make([]byte, 16) + _, _ = rand.Read(id) + + m.SetExpirationEpoch(89) + m.SetSplitID(id) + m.SetMembers(refstest.GenerateObjectIDs(false)) + } + + return m +} diff --git a/api/tombstone/types.go b/api/tombstone/types.go new file mode 100644 index 0000000..f28c69d --- /dev/null +++ b/api/tombstone/types.go @@ -0,0 +1,57 @@ +package tombstone + +import ( + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" +) + +// Tombstone is a unified structure of Tombstone +// message from proto definition. +type Tombstone struct { + exp uint64 + + splitID []byte + + members []refs.ObjectID +} + +// GetExpirationEpoch returns number of tombstone expiration epoch. +func (s *Tombstone) GetExpirationEpoch() uint64 { + if s != nil { + return s.exp + } + + return 0 +} + +// SetExpirationEpoch sets number of tombstone expiration epoch. +func (s *Tombstone) SetExpirationEpoch(v uint64) { + s.exp = v +} + +// GetSplitID returns identifier of split object hierarchy. +func (s *Tombstone) GetSplitID() []byte { + if s != nil { + return s.splitID + } + + return nil +} + +// SetSplitID sets identifier of split object hierarchy. +func (s *Tombstone) SetSplitID(v []byte) { + s.splitID = v +} + +// GetMembers returns list of objects to be deleted. +func (s *Tombstone) GetMembers() []refs.ObjectID { + if s != nil { + return s.members + } + + return nil +} + +// SetMembers sets list of objects to be deleted. +func (s *Tombstone) SetMembers(v []refs.ObjectID) { + s.members = v +} diff --git a/api/util/pool/buffer.go b/api/util/pool/buffer.go new file mode 100644 index 0000000..e0a7185 --- /dev/null +++ b/api/util/pool/buffer.go @@ -0,0 +1,54 @@ +package pool + +import ( + "sync" +) + +// Buffer contains a byte slice. +type Buffer struct { + Data []byte +} + +// BufferPool manages a pool of Buffers. +type BufferPool struct { + poolSliceSize uint32 // Size for the buffer slices in the pool. + buffersPool *sync.Pool +} + +// NewBufferPool creates a BufferPool with a specified size. +func NewBufferPool(poolSliceSize uint32) BufferPool { + pool := sync.Pool{ + New: func() any { + return new(Buffer) + }, + } + return BufferPool{poolSliceSize: poolSliceSize, buffersPool: &pool} +} + +// Get retrieves a Buffer from the pool or creates a new one if necessary. +// It ensures the buffer's capacity is at least the specified size. +func (pool BufferPool) Get(size uint32) *Buffer { + result := pool.buffersPool.Get().(*Buffer) + + if cap(result.Data) < int(size) { + result.Data = make([]byte, size) + } else { + result.Data = result.Data[:size] + } + return result +} + +// Put returns a Buffer to the pool if its capacity does not exceed poolSliceSize. +func (pool BufferPool) Put(buf *Buffer) { + if cap(buf.Data) > int(pool.poolSliceSize) { + return + } + + buf.Data = buf.Data[:0] + pool.buffersPool.Put(buf) +} + +// PoolSliceSize returns the size for buffer slices in the pool. +func (pool BufferPool) PoolSliceSize() uint32 { + return uint32(pool.poolSliceSize) +} diff --git a/api/util/pool/marshal.go b/api/util/pool/marshal.go new file mode 100644 index 0000000..107df28 --- /dev/null +++ b/api/util/pool/marshal.go @@ -0,0 +1,7 @@ +package pool + +import ( + "github.com/VictoriaMetrics/easyproto" +) + +var MarshalerPool easyproto.MarshalerPool diff --git a/api/util/proto/encoding/compat.go b/api/util/proto/encoding/compat.go new file mode 100644 index 0000000..09d45e6 --- /dev/null +++ b/api/util/proto/encoding/compat.go @@ -0,0 +1,22 @@ +package encoding + +import ( + _ "google.golang.org/grpc/encoding/proto" // Ensure default codec is registered before our one. + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/protoadapt" +) + +// messageV2Of converts v to a proto.Message. +// This is needed for this library to continue working in presence of external gRPC packages, +// such as opentelemetry gRPC exporter. +// Copied from https://github.com/grpc/grpc-go/blob/e524655becd8d4c7ba9e8687faef456e495e341e/encoding/proto/proto.go#L59. +func messageV2Of(v any) proto.Message { + switch v := v.(type) { + case protoadapt.MessageV1: + return protoadapt.MessageV2Of(v) + case protoadapt.MessageV2: + return v + } + + return nil +} diff --git a/api/util/proto/encoding/json.go b/api/util/proto/encoding/json.go new file mode 100644 index 0000000..3456a40 --- /dev/null +++ b/api/util/proto/encoding/json.go @@ -0,0 +1,48 @@ +package encoding + +import ( + "encoding/json" + "fmt" + + "google.golang.org/grpc/encoding" + "google.golang.org/protobuf/encoding/protojson" +) + +// JSONCodec is easyjson codec used for code generated by protogen. +// It is binary-level compatible with the standard protojson format, thus uses the same name. +type JSONCodec struct{} + +var _ encoding.Codec = JSONCodec{} + +func init() { + encoding.RegisterCodec(JSONCodec{}) +} + +// Name implements the encoding.Codec interface. +func (JSONCodec) Name() string { return "json" } + +// Marshal implements the encoding.Codec interface. +func (JSONCodec) Marshal(v any) ([]byte, error) { + switch v := v.(type) { + case json.Marshaler: + return json.Marshal(v) + default: + if v := messageV2Of(v); v != nil { + return protojson.Marshal(v) + } + return nil, fmt.Errorf("failed to marshal, message is %T, want proto.Message", v) + } +} + +// Unmarshal implements the encoding.Codec interface. +func (JSONCodec) Unmarshal(data []byte, v any) error { + switch v := v.(type) { + case json.Unmarshaler: + return json.Unmarshal(data, v) + default: + if v := messageV2Of(v); v != nil { + return protojson.Unmarshal(data, v) + } + return fmt.Errorf("failed to unmarshal, message is %T, want proto.Message", v) + } +} diff --git a/api/util/proto/encoding/proto.go b/api/util/proto/encoding/proto.go new file mode 100644 index 0000000..5f3c556 --- /dev/null +++ b/api/util/proto/encoding/proto.go @@ -0,0 +1,57 @@ +package encoding + +import ( + "fmt" + + "google.golang.org/grpc/encoding" + "google.golang.org/protobuf/proto" +) + +// ProtoCodec is easyproto codec used for code generated by protogen. +// It is binary-level compatible with the standard proto codec, thus uses the same name. +type ProtoCodec struct{} + +// ProtoMarshaler is an interface accepted by ProtoCodec.Marshal. +type ProtoMarshaler interface { + MarshalProtobuf([]byte) []byte +} + +// ProtoUnmarshaler is an interface accepted by ProtoCodec.Unmarshal. +type ProtoUnmarshaler interface { + UnmarshalProtobuf([]byte) error +} + +var _ encoding.Codec = ProtoCodec{} + +func init() { + encoding.RegisterCodec(ProtoCodec{}) +} + +// Name implements the encoding.Codec interface. +func (ProtoCodec) Name() string { return "proto" } + +// Marshal implements the encoding.Codec interface. +func (ProtoCodec) Marshal(v any) ([]byte, error) { + switch v := v.(type) { + case ProtoMarshaler: + return v.MarshalProtobuf(nil), nil + default: + if v := messageV2Of(v); v != nil { + return proto.Marshal(v) + } + return nil, fmt.Errorf("failed to marshal, message is %T, want proto.Message", v) + } +} + +// Unmarshal implements the encoding.Codec interface. +func (ProtoCodec) Unmarshal(data []byte, v any) error { + switch v := v.(type) { + case ProtoUnmarshaler: + return v.UnmarshalProtobuf(data) + default: + if v := messageV2Of(v); v != nil { + return proto.Unmarshal(data, v) + } + return fmt.Errorf("failed to unmarshal, message is %T, want proto.Message", v) + } +} diff --git a/api/util/proto/marshal.go b/api/util/proto/marshal.go new file mode 100644 index 0000000..5016255 --- /dev/null +++ b/api/util/proto/marshal.go @@ -0,0 +1,413 @@ +/* +This package contains help functions for stable marshaller. Their usage is +totally optional. One can implement fast stable marshaller without these +runtime function calls. +*/ + +package proto + +import ( + "encoding/binary" + "math" + "math/bits" + + "google.golang.org/protobuf/encoding/protowire" +) + +type ( + stableMarshaler interface { + StableMarshal([]byte) []byte + stableSizer + } + + stableSizer interface { + StableSize() int + } + + setMarshalData[T any] interface { + SetMarshalData([]byte) + StableSize() int + ~*T + } +) + +func BytesMarshal(field int, buf, v []byte) int { + return bytesMarshal(field, buf, v) +} + +func BytesSize(field int, v []byte) int { + return bytesSize(field, v) +} + +func bytesMarshal[T ~[]byte | ~string](field int, buf []byte, v T) int { + if len(v) == 0 { + return 0 + } + return bytesMarshalNoCheck(field, buf, v) +} + +func bytesMarshalNoCheck[T ~[]byte | ~string](field int, buf []byte, v T) int { + prefix := protowire.EncodeTag(protowire.Number(field), protowire.BytesType) + + // buf length check can prevent panic at PutUvarint, but it will make + // marshaller a bit slower. + i := binary.PutUvarint(buf, uint64(prefix)) + i += binary.PutUvarint(buf[i:], uint64(len(v))) + i += copy(buf[i:], v) + + return i +} + +func bytesSize[T ~[]byte | ~string](field int, v T) int { + if len(v) == 0 { + return 0 + } + return bytesSizeNoCheck(field, v) +} + +func bytesSizeNoCheck[T ~[]byte | ~string](field int, v T) int { + return protowire.SizeGroup(protowire.Number(field), protowire.SizeBytes(len(v))) +} + +func StringMarshal(field int, buf []byte, v string) int { + return bytesMarshal(field, buf, v) +} + +func StringSize(field int, v string) int { + return bytesSize(field, v) +} + +func BoolMarshal(field int, buf []byte, v bool) int { + if !v { + return 0 + } + + prefix := protowire.EncodeTag(protowire.Number(field), protowire.VarintType) + + // buf length check can prevent panic at PutUvarint, but it will make + // marshaller a bit slower. + i := binary.PutUvarint(buf, uint64(prefix)) + const boolTrueValue = 0x1 + buf[i] = boolTrueValue + + return i + 1 +} + +func BoolSize(field int, v bool) int { + if !v { + return 0 + } + const boolLength = 1 + return protowire.SizeGroup(protowire.Number(field), boolLength) +} + +func UInt64Marshal(field int, buf []byte, v uint64) int { + if v == 0 { + return 0 + } + + prefix := protowire.EncodeTag(protowire.Number(field), protowire.VarintType) + + // buf length check can prevent panic at PutUvarint, but it will make + // marshaller a bit slower. + i := binary.PutUvarint(buf, uint64(prefix)) + i += binary.PutUvarint(buf[i:], v) + + return i +} + +func UInt64Size(field int, v uint64) int { + if v == 0 { + return 0 + } + return protowire.SizeGroup(protowire.Number(field), protowire.SizeVarint(v)) +} + +func Int64Marshal(field int, buf []byte, v int64) int { + return UInt64Marshal(field, buf, uint64(v)) +} + +func Int64Size(field int, v int64) int { + return UInt64Size(field, uint64(v)) +} + +func UInt32Marshal(field int, buf []byte, v uint32) int { + return UInt64Marshal(field, buf, uint64(v)) +} + +func UInt32Size(field int, v uint32) int { + return UInt64Size(field, uint64(v)) +} + +func Int32Marshal(field int, buf []byte, v int32) int { + return UInt64Marshal(field, buf, uint64(uint32(v))) +} + +func Int32Size(field int, v int32) int { + return UInt64Size(field, uint64(uint32(v))) +} + +func EnumMarshal(field int, buf []byte, v int32) int { + return UInt64Marshal(field, buf, uint64(uint32(v))) +} + +func EnumSize(field int, v int32) int { + return UInt64Size(field, uint64(uint32(v))) +} + +func RepeatedBytesMarshal(field int, buf []byte, v [][]byte) int { + var offset int + + for i := range v { + offset += bytesMarshalNoCheck(field, buf[offset:], v[i]) + } + + return offset +} + +func RepeatedBytesSize(field int, v [][]byte) (size int) { + for i := range v { + size += bytesSizeNoCheck(field, v[i]) + } + + return size +} + +func RepeatedStringMarshal(field int, buf []byte, v []string) int { + var offset int + + for i := range v { + offset += bytesMarshalNoCheck(field, buf[offset:], v[i]) + } + + return offset +} + +func RepeatedStringSize(field int, v []string) (size int) { + for i := range v { + size += bytesSizeNoCheck(field, v[i]) + } + + return size +} + +func repeatedUIntSize[T ~uint64 | ~int64 | ~uint32 | ~int32](field int, v []T) (size, arraySize int) { + if len(v) == 0 { + return 0, 0 + } + + for i := range v { + arraySize += protowire.SizeVarint(uint64(v[i])) + } + + size = protowire.SizeGroup(protowire.Number(field), protowire.SizeBytes(arraySize)) + + return +} + +func repeatedUIntMarshal[T ~uint64 | ~int64 | ~uint32 | ~int32](field int, buf []byte, v []T) int { + if len(v) == 0 { + return 0 + } + + prefix := protowire.EncodeTag(protowire.Number(field), protowire.BytesType) + offset := binary.PutUvarint(buf, uint64(prefix)) + + _, arrSize := repeatedUIntSize(field, v) + offset += binary.PutUvarint(buf[offset:], uint64(arrSize)) + for i := range v { + offset += binary.PutUvarint(buf[offset:], uint64(v[i])) + } + + return offset +} + +func RepeatedUInt64Marshal(field int, buf []byte, v []uint64) int { + return repeatedUIntMarshal(field, buf, v) +} + +func RepeatedUInt64Size(field int, v []uint64) (size, arraySize int) { + return repeatedUIntSize(field, v) +} + +func RepeatedInt64Marshal(field int, buf []byte, v []int64) int { + return repeatedUIntMarshal(field, buf, v) +} + +func RepeatedInt64Size(field int, v []int64) (size, arraySize int) { + return repeatedUIntSize(field, v) +} + +func RepeatedUInt32Marshal(field int, buf []byte, v []uint32) int { + return repeatedUIntMarshal(field, buf, v) +} + +func RepeatedUInt32Size(field int, v []uint32) (size, arraySize int) { + return repeatedUIntSize(field, v) +} + +func RepeatedInt32Marshal(field int, buf []byte, v []int32) int { + if len(v) == 0 { + return 0 + } + + prefix := protowire.EncodeTag(protowire.Number(field), protowire.BytesType) + offset := binary.PutUvarint(buf, uint64(prefix)) + _, arrSize := RepeatedInt32Size(field, v) + offset += binary.PutUvarint(buf[offset:], uint64(arrSize)) + for i := range v { + offset += binary.PutUvarint(buf[offset:], uint64(uint32(v[i]))) + } + return offset +} + +func RepeatedInt32Size(field int, v []int32) (size, arraySize int) { + if len(v) == 0 { + return 0, 0 + } + for i := range v { + arraySize += protowire.SizeVarint(uint64(uint32(v[i]))) + } + return protowire.SizeGroup(protowire.Number(field), protowire.SizeBytes(arraySize)), arraySize +} + +// VarUIntSize returns length of varint byte sequence for uint64 value 'x'. +func VarUIntSize(x uint64) int { + return (bits.Len64(x|1) + 6) / 7 +} + +type ptrStableMarshaler[T any] interface { + stableMarshaler + ~*T +} + +type ptrStableSizer[T any] interface { + stableSizer + ~*T +} + +func NestedStructureMarshal[T any, M ptrStableMarshaler[T]](field int64, buf []byte, v M) int { + if v == nil { + return 0 + } + + return NestedStructureMarshalUnchecked(field, buf, v) +} + +func NestedStructureMarshalUnchecked[T stableMarshaler](field int64, buf []byte, v T) int { + n := v.StableSize() + prefix := protowire.EncodeTag(protowire.Number(field), protowire.BytesType) + offset := binary.PutUvarint(buf, prefix) + offset += binary.PutUvarint(buf[offset:], uint64(n)) + v.StableMarshal(buf[offset:]) + + return offset + n +} + +// NestedStructureSetMarshalData calculates offset for field in parentData +// and calls SetMarshalData for nested structure. +// +// Returns marshalled data length of nested structure. +func NestedStructureSetMarshalData[T any, M setMarshalData[T]](field int64, parentData []byte, v M) int { + if v == nil { + return 0 + } + + if parentData == nil { + v.SetMarshalData(nil) + return 0 + } + + n := v.StableSize() + buf := make([]byte, binary.MaxVarintLen64) + prefix := protowire.EncodeTag(protowire.Number(field), protowire.BytesType) + offset := binary.PutUvarint(buf, prefix) + offset += binary.PutUvarint(buf, uint64(n)) + + v.SetMarshalData(parentData[offset : offset+n]) + + return offset + n +} + +func NestedStructureSize[T any, M ptrStableSizer[T]](field int64, v M) (size int) { + if v == nil { + return 0 + } + + return NestedStructureSizeUnchecked(field, v) +} + +func NestedStructureSizeUnchecked[T stableSizer](field int64, v T) int { + n := v.StableSize() + return protowire.SizeGroup(protowire.Number(field), protowire.SizeBytes(n)) +} + +func Fixed64Marshal(field int, buf []byte, v uint64) int { + if v == 0 { + return 0 + } + + prefix := protowire.EncodeTag(protowire.Number(field), protowire.Fixed64Type) + + // buf length check can prevent panic at PutUvarint, but it will make + // marshaller a bit slower. + i := binary.PutUvarint(buf, uint64(prefix)) + binary.LittleEndian.PutUint64(buf[i:], v) + + return i + 8 +} + +func Fixed64Size(fNum int, v uint64) int { + if v == 0 { + return 0 + } + return protowire.SizeGroup(protowire.Number(fNum), protowire.SizeFixed64()) +} + +func Float64Marshal(field int, buf []byte, v float64) int { + if v == 0 { + return 0 + } + + prefix := protowire.EncodeTag(protowire.Number(field), protowire.Fixed64Type) + + i := binary.PutUvarint(buf, uint64(prefix)) + binary.LittleEndian.PutUint64(buf[i:], math.Float64bits(v)) + + return i + 8 +} + +func Float64Size(fNum int, v float64) int { + if v == 0 { + return 0 + } + return protowire.SizeGroup(protowire.Number(fNum), protowire.SizeFixed64()) +} + +// Fixed32Marshal encodes uint32 value to Protocol Buffers fixed32 field with specified number, +// and writes it to specified buffer. Returns number of bytes written. +// +// Panics if the buffer is undersized. +func Fixed32Marshal(field int, buf []byte, v uint32) int { + if v == 0 { + return 0 + } + + prefix := protowire.EncodeTag(protowire.Number(field), protowire.Fixed32Type) + + // buf length check can prevent panic at PutUvarint, but it will make + // marshaller a bit slower. + i := binary.PutUvarint(buf, uint64(prefix)) + binary.LittleEndian.PutUint32(buf[i:], v) + + return i + 4 +} + +// Fixed32Size returns number of bytes required to encode uint32 value to Protocol Buffers fixed32 field +// with specified number. +func Fixed32Size(fNum int, v uint32) int { + if v == 0 { + return 0 + } + return protowire.SizeGroup(protowire.Number(fNum), protowire.SizeFixed32()) +} diff --git a/api/util/proto/marshal_test.go b/api/util/proto/marshal_test.go new file mode 100644 index 0000000..a635bb6 --- /dev/null +++ b/api/util/proto/marshal_test.go @@ -0,0 +1,247 @@ +package proto_test + +import ( + "math" + "math/rand" + "testing" + + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/util/proto/test" + generated "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/util/proto/test/custom" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/encoding/protojson" + goproto "google.golang.org/protobuf/proto" +) + +type protoInt interface { + ~int32 | ~uint32 | ~int64 | ~uint64 +} + +func nonZero[T protoInt]() T { + var r T + for r == 0 { + r = T(rand.Uint64()) + } + return r +} + +func TestStableMarshalSingle(t *testing.T) { + t.Run("empty", func(t *testing.T) { + t.Run("proto", func(t *testing.T) { + input := &generated.Primitives{} + require.Zero(t, input.StableSize()) + + r := input.MarshalProtobuf(nil) + require.Empty(t, r) + }) + t.Run("json", func(t *testing.T) { + input := &generated.Primitives{} + r, err := input.MarshalJSON() + require.NoError(t, err) + require.NotEmpty(t, r) + + var actual test.Primitives + require.NoError(t, protojson.Unmarshal(r, &actual)) + + t.Run("protojson compatibility", func(t *testing.T) { + data, err := protojson.MarshalOptions{EmitUnpopulated: true}.Marshal(&actual) + require.NoError(t, err) + require.JSONEq(t, string(data), string(r)) + }) + + var actualFrostfs generated.Primitives + require.NoError(t, actualFrostfs.UnmarshalJSON(r)) + require.Equal(t, input, &actualFrostfs) + + primitivesEqual(t, input, &actual) + }) + }) + + marshalCases := []struct { + name string + input *generated.Primitives + }{ + {name: "bytes", input: &generated.Primitives{FieldA: []byte{1, 2, 3}}}, + {name: "string", input: &generated.Primitives{FieldB: "123"}}, + {name: "bool", input: &generated.Primitives{FieldC: true}}, + {name: "int32", input: &generated.Primitives{FieldD: -10}}, + {name: "uint32", input: &generated.Primitives{FieldE: nonZero[uint32]()}}, + {name: "int64", input: &generated.Primitives{FieldF: nonZero[int64]()}}, + {name: "uint64", input: &generated.Primitives{FieldG: nonZero[uint64]()}}, + {name: "uint64", input: &generated.Primitives{FieldI: nonZero[uint64]()}}, + {name: "float64", input: &generated.Primitives{FieldJ: math.Float64frombits(12345677890)}}, + {name: "fixed32", input: &generated.Primitives{FieldK: nonZero[uint32]()}}, + {name: "enum, positive", input: &generated.Primitives{FieldH: generated.Primitives_POSITIVE}}, + {name: "enum, negative", input: &generated.Primitives{FieldH: generated.Primitives_NEGATIVE}}, + {name: "oneof, first", input: &generated.Primitives{FieldM: &generated.Primitives_FieldMa{FieldMa: []byte{4, 2}}}}, + {name: "oneof, second", input: &generated.Primitives{FieldM: &generated.Primitives_FieldMe{FieldMe: nonZero[uint32]()}}}, + } + for _, tc := range marshalCases { + t.Run(tc.name, func(t *testing.T) { + t.Run("proto", func(t *testing.T) { + r := tc.input.MarshalProtobuf(nil) + require.Equal(t, len(r), tc.input.StableSize()) + require.NotEmpty(t, r) + + var actual test.Primitives + require.NoError(t, goproto.Unmarshal(r, &actual)) + + var actualFrostfs generated.Primitives + require.NoError(t, actualFrostfs.UnmarshalProtobuf(r)) + require.Equal(t, tc.input, &actualFrostfs) + + primitivesEqual(t, tc.input, &actual) + }) + t.Run("json", func(t *testing.T) { + r, err := tc.input.MarshalJSON() + require.NoError(t, err) + require.NotEmpty(t, r) + + var actual test.Primitives + require.NoError(t, protojson.Unmarshal(r, &actual)) + + t.Run("protojson compatibility", func(t *testing.T) { + data, err := protojson.MarshalOptions{EmitUnpopulated: true}.Marshal(&actual) + require.NoError(t, err) + require.JSONEq(t, string(data), string(r)) + }) + + var actualFrostfs generated.Primitives + require.NoError(t, actualFrostfs.UnmarshalJSON(r)) + require.Equal(t, tc.input, &actualFrostfs) + + primitivesEqual(t, tc.input, &actual) + }) + }) + } +} + +func primitivesEqual(t *testing.T, a *generated.Primitives, b *test.Primitives) { + // Compare each field directly, because proto-generated code has private fields. + require.Equal(t, len(a.FieldA), len(b.FieldA)) + require.Equal(t, a.FieldA, b.FieldA) + require.Equal(t, a.FieldB, b.FieldB) + require.Equal(t, a.FieldC, b.FieldC) + require.Equal(t, a.FieldD, b.FieldD) + require.Equal(t, a.FieldE, b.FieldE) + require.Equal(t, a.FieldF, b.FieldF) + require.Equal(t, a.FieldG, b.FieldG) + require.Equal(t, a.FieldI, b.FieldI) + require.Equal(t, a.FieldJ, b.FieldJ) + require.Equal(t, a.FieldK, b.FieldK) + require.EqualValues(t, a.FieldH, b.FieldH) + require.Equal(t, a.GetFieldMa(), b.GetFieldMa()) + require.Equal(t, a.GetFieldMe(), b.GetFieldMe()) + require.Equal(t, a.GetFieldAux().GetInnerField(), b.GetFieldAux().GetInnerField()) +} + +func repPrimitivesEqual(t *testing.T, a *generated.RepPrimitives, b *test.RepPrimitives) { + // Compare each field directly, because proto-generated code has private fields. + require.Equal(t, a.FieldA, b.FieldA) + require.Equal(t, a.FieldB, b.FieldB) + require.Equal(t, a.FieldC, b.FieldC) + require.Equal(t, a.FieldD, b.FieldD) + require.Equal(t, a.FieldE, b.FieldE) + require.Equal(t, a.FieldF, b.FieldF) + require.Equal(t, a.FieldFu, b.FieldFu) + require.Equal(t, len(a.GetFieldAux()), len(b.GetFieldAux())) + for i := range a.FieldAux { + require.Equal(t, a.GetFieldAux()[i].GetInnerField(), b.GetFieldAux()[i].GetInnerField()) + } +} + +func randIntSlice[T protoInt](n int, includeZero bool) []T { + r := make([]T, n) + if n == 0 { + return r + } + for i := range r { + r[i] = T(rand.Uint64()) + } + if includeZero { + r[0] = 0 + } + return r +} + +func uint32SliceToAux(s []uint32) []generated.RepPrimitives_Aux { + r := make([]generated.RepPrimitives_Aux, len(s)) + for i := range s { + r[i] = generated.RepPrimitives_Aux{InnerField: s[i]} + } + return r +} + +func TestStableMarshalRep(t *testing.T) { + t.Run("empty", func(t *testing.T) { + marshalCases := []struct { + name string + input *generated.RepPrimitives + }{ + {name: "default", input: &generated.RepPrimitives{}}, + {name: "bytes", input: &generated.RepPrimitives{FieldA: [][]byte{}}}, + {name: "string", input: &generated.RepPrimitives{FieldB: []string{}}}, + {name: "int32", input: &generated.RepPrimitives{FieldC: []int32{}}}, + {name: "uint32", input: &generated.RepPrimitives{FieldD: []uint32{}}}, + {name: "int64", input: &generated.RepPrimitives{FieldE: []int64{}}}, + {name: "uint64", input: &generated.RepPrimitives{FieldF: []uint64{}}}, + {name: "uint64", input: &generated.RepPrimitives{FieldFu: []uint64{}}}, + } + + for _, tc := range marshalCases { + t.Run(tc.name, func(t *testing.T) { + require.Zero(t, tc.input.StableSize()) + + r := tc.input.MarshalProtobuf(nil) + require.Empty(t, r) + }) + } + }) + + marshalCases := []struct { + name string + input *generated.RepPrimitives + }{ + {name: "bytes", input: &generated.RepPrimitives{FieldA: [][]byte{{1, 2, 3}}}}, + {name: "string", input: &generated.RepPrimitives{FieldB: []string{"123"}}}, + {name: "int32", input: &generated.RepPrimitives{FieldC: randIntSlice[int32](1, true)}}, + {name: "int32", input: &generated.RepPrimitives{FieldC: randIntSlice[int32](2, true)}}, + {name: "int32", input: &generated.RepPrimitives{FieldC: randIntSlice[int32](2, false)}}, + {name: "uint32", input: &generated.RepPrimitives{FieldD: randIntSlice[uint32](1, true)}}, + {name: "uint32", input: &generated.RepPrimitives{FieldD: randIntSlice[uint32](2, true)}}, + {name: "uint32", input: &generated.RepPrimitives{FieldD: randIntSlice[uint32](2, false)}}, + {name: "int64", input: &generated.RepPrimitives{FieldE: randIntSlice[int64](1, true)}}, + {name: "int64", input: &generated.RepPrimitives{FieldE: randIntSlice[int64](2, true)}}, + {name: "int64", input: &generated.RepPrimitives{FieldE: randIntSlice[int64](2, false)}}, + {name: "uint64", input: &generated.RepPrimitives{FieldF: randIntSlice[uint64](1, true)}}, + {name: "uint64", input: &generated.RepPrimitives{FieldF: randIntSlice[uint64](2, true)}}, + {name: "uint64", input: &generated.RepPrimitives{FieldF: randIntSlice[uint64](2, false)}}, + {name: "uint64", input: &generated.RepPrimitives{FieldFu: randIntSlice[uint64](1, true)}}, + {name: "uint64", input: &generated.RepPrimitives{FieldFu: randIntSlice[uint64](2, true)}}, + {name: "uint64", input: &generated.RepPrimitives{FieldFu: randIntSlice[uint64](2, false)}}, + {name: "message", input: &generated.RepPrimitives{FieldAux: uint32SliceToAux(randIntSlice[uint32](1, true))}}, + {name: "message", input: &generated.RepPrimitives{FieldAux: uint32SliceToAux(randIntSlice[uint32](2, true))}}, + {name: "message", input: &generated.RepPrimitives{FieldAux: uint32SliceToAux(randIntSlice[uint32](2, false))}}, + } + for _, tc := range marshalCases { + t.Run(tc.name, func(t *testing.T) { + t.Run("proto", func(t *testing.T) { + r := tc.input.MarshalProtobuf(nil) + require.Equal(t, len(r), tc.input.StableSize()) + require.NotEmpty(t, r) + + var actual test.RepPrimitives + require.NoError(t, goproto.Unmarshal(r, &actual)) + repPrimitivesEqual(t, tc.input, &actual) + }) + t.Run("json", func(t *testing.T) { + r, err := tc.input.MarshalJSON() + require.NoError(t, err) + require.NotEmpty(t, r) + + var actual test.RepPrimitives + require.NoError(t, protojson.Unmarshal(r, &actual)) + repPrimitivesEqual(t, tc.input, &actual) + }) + }) + } +} diff --git a/api/util/proto/test/custom/test_frostfs.pb.go b/api/util/proto/test/custom/test_frostfs.pb.go new file mode 100644 index 0000000000000000000000000000000000000000..c9b269941f85463e74ac5bb2802646c8b230f27e GIT binary patch literal 35040 zcmeHQZEq7v68`M`idjpyJLZBDLN2??iIbApPMoX*I$-w$hqy^HhFSb3za<>vzu!~U zFH=3!_Kbr`01>eZZdZ3dRb5?O{Zf^!t>9>Q6$fwQK|GG8@l|l~AsCH^)8XYqls$Yq zeApciC)4hv9yFc?=TBb*%|`o0ePd%3UA~Xr#=$h6OgA=?{%AO!2H{5KugP!_RO7+r z@G2R+-J*}xjY_va4XXGb{y7>BdqMSWGOe4IlRj zY(=AFYc@@KTU3{tAb_`SgDRsD1M#!k*)pwAgVE$eitOF&qJBB-Z~c*6PKV

crD= zayi+uRH*S+FTRP#48V~0qog;UF%^k!OOX)m^*EUp5i1%{Gmh(I9Ha5!@NF-yza93X z!Q1+9{C11KyqI+@cvV8=s5+UBFNcG9P}TpaZqzn5rXNOe@NAs)lW8)KCvTn)`*CwH z>j%kT`gmt!12rZ*{DS7?`Puo?KhFbiy(hu;Mnw=md-}ZnqWwp60r4Y;_`G?1u!Q*G zBZ54S#-xv;4+HwmAnM1#lb|1sUNQdHU=_;xaidb%-VcJRMqb@S!6Pa#=(yw|imC8YR7`w}#_>G;I&2 zA-LJwMZL}7(ROX)lLhy{BlB9&8V~y#;Y1^>1s7xtO5kK!zM7;6AKYL7J^h69T8e)P zn<820M!iW4pgDCunB5Sh+2xeLv@0==l8!dkKmQ)w|msN2>S zlq$OD#m|%f#eq_UNicmE2NNn7c7q#O0JUJipafmkjXLV7swC0bIGzO8$@HD7M^mrM zvgI+I1n;6bRuO8FzPd;T(f9*5U-v2$Nl<`-wug)b169+S1l4#FK*&;+VQnx?ney*X z6yW+xDDmSRVl8~M8Qj#~tBvAxSiOt}gW(jDH@XT2XhP3EOxwRrs+(Bb(p4REtBSFvnNpcx%3i*se!0(c zto5`qTt<^PzygT*kWLqrSFWOIWL6qf(qlud5ze3V!eW;e55k!-fEuBKm-fQY7#lP> zErxKYZ*&CM_@gH-L;@{XsHm7TX%jFa+R&?|=tjy^wi>?ewfj&V%z8c6 z1_g+RqnnIjxWJ8C^mPpa7yk0`7l0@2B~4U>^r_+yZ4y!CQxL;PU{$XuO3XcW8`QK= zj_zn2cN2CQ;5K6Ps{awb!GEgzaHCD*8ndcFJy555c1Rt-R}j2|=o1jBrN>&Dg?eEr zR<&I`x-@~T;bNOb5*V{`@E)c9JMC0HHbA$}(~XtHc4`Oo=P~%uYBE;(fTd~4Jj^!% z!}LJydQ_)MAto<|qu=9s+#^iMpx&OqF&Xo^he73nb7%#$T#s{-*5I)Q35@Mz){n1f zv1B`fvghxU5q}n{gyKfrOZr-I$Ta`NJ?K)53-|Iq{-Dvk9898atPCZ*n2Y_3rM#gomtb`o3)!KtE;2HzOy#5RhYD~Ht4#?-<3?A<&QgD@B ziJ13;t1DiHXf0HfS~<7_=n#HJbLv~!U*)}5DqYN}5q2N=k#hv4T`HuC^q-ZkmKDlS zl#UYbe=>>y0;vb=Dr9!IVk^KydSHAo>oe0o^q!zgzU%?^0~Mw{)LR>e)S*4Jv`1?D zPc7|PA#Z1v_QbbAbmV(tX*)qO5uOl_WrwWq%6q)k_jhTH%n~m~#ogOw zYFH!6TTWfeTjQ(T)2(Yi$DT;Kol|ocX2;$2DI3RRJGARl(>6zTh@F)p+J>RiWJfu& zw%tPRZ1X0Pn``9g#9nh}JMFibBSeFHySn4Yw&PZgjvBOtyO!`cN7zbk;www}4@=q3 zQ>t00JKwXEr+G?hQ*WJjwtuyhXE{nbB;*DklNe!Z9`A%&m?yN`f{ze|IV&@qh~*G_~!Xjvd1p=3AlqHe?(?$Q{_e&Ut;p@WPC z{G8)VJ-&jXs^b%u-|jZFLG(z~2X(C`3c^Mz_D zL^54YwWg<<-oIomnNzRjsmC@8-MNO%sdntCM&040d1u?Tb56asr=B)_sOXwKr{bxn zVq-YNp(pCOM$oBu=BdXW!op>3qNn(@04(Cafi_AL*O09UNK>sDFECCgg&zGKZw*uu-3thOoo5 zZYe;S-FZ2SE4?+S#FE3|T3~5S)8F_J;|j-%%6+5lUgl^~8C4pC&pTOE9XO|ostDUm zeWJ*l>m5GrEKoXA&Pf}@3OxR?kIT^OP>cu4YH)BXUoch744t-18{u} zB5yip=8AJa_}euuU(K;N_iK(mpeJd^0Hhpm-P*!y&02sfO=kT7mmunfj+Akzh==e9M4bqH7!exXzh3w{>3)=;a}MNJ!2hv8f| z%@;Eo75PntsE&Y2JVII`DtKBcCi9ZW%dvrV1X$Fz1VzqMA*cpGVP}Bj{=xx-zm=j| za2Jj9RXuzSAmWB4Byyh$AvFPMRuU6jt`#sffl0M2L6HYl2&$#zgd2%MIl<{#0aHuK zX>V6TA|I*{(y^9P8BFlIR={+u<>Z1QH>wa+dj(MKl|Z$*TPGw)XGInCG-TxBKb04(>|=+33Pt#?9i+8 zLY;>*3&BfeLy4K9rAL6gW_yd383KGK$DoA%6DD^8Q2Uu7C~)iN=Jls|{Fc1}%iOcW zuUUEuD_Vlc?(-R)y@j(cuJB^)dwD|F<)<_S&*x}AqjzI+KJm-BLp)C1+g0bohKP;; zBQ5a{m++))W|e6Xyc(Nl;!g4QSj ztu0>`=sV227}I76Z2F`|3yz+A+>zi~CBWfXElrs4mny%1B^|V{d+8Y-w(R`&Pd&MZ zm_wJuzWr#aFd+NzRkV6X>>jV3T^hMX{2t#szwJBaw|(#Yo|fRZrQR@^R~htl>5jDT ztOPpO63}a@I|6r70FK|_LfPf(EVUxei{l69X;>aF!+Lq0b0}VR?Nx?aeZ}nS_slmp zbmFRQB%XiKn_Tw%`21eFsd|$`@0`iPXP0gF4ZV8R?|1;Ycl|U7xF_HcR?o|RUb{Py zmY``~Gnu~Y=aW{0KXQDNymMmdpaQOcA|4S~V#K7IsisPK-Jf;H4W zCm*PxPEg1o==hDwv_B%Nh?oWO=!GpFz30NWH41fAVUbjg==ot2H=^vCil)FfT*ju( zoIM_Z*alSa%&e-7N*){BK!iGR6XX>Fkv4#Az)XX5<>G7bDBmDmjL7DAZ{ajXS0%p2 z8u`X}<>J=(-VW$KC&C3w)cONl)Z)tPUM9YU*E70=@iE)XGdo)^x9sEIWjqh_OZPiI zep`8d!S3Gfml#~!q;RwP!dE^C#2g#c%SSIUL~rmCGfOu|K4y>e%+lblky|;q>tk1e zT+A%ZWT1r|zvt@CNAKg{?nmo%lNuz-rEM))JVg01a+(~>N zPZ7EX^YMF<=ht&X#mrNr)`%h$um0f7D~ss#hC^?85J|2Nf9ZC|?m8e$UJ%u~$1#<# z3CO0hbUUQdl*s)M+L4(2PnFb8i3acjVfycx8?$&*hx$1Ru%uy_fF0s18HGvsh}1P? z3oMxo#58@CN6NC%x~zp$qO#I(<${nGA*wLX+To@J!?z;de;9Pt@VCcj#pq9CQ!nWhgFWi1$s)8T!WOzY!8$TKR;8?N^bMK*FkJn(~gj zJVHPPRyb0^j2@Y`D&6#{m)P!TBdvP^u|!Rp4Zp$J5}*u4w~R^l+-=kQ9d%j7cXj!o zRlKZ2SVAVG+1%OEajwpCq$iBNw_RKZiFq=0VtwbhunvhOQ;CYQBLJA{{gnK|%wylZ zJ}%#oonm1noELcnw!9Jz_mWyH#(&2nv6i^ZwQWi$^E^t&Ept!_GlLjofG!zFoa-wM z^>yR+>^nrn{8Fgzl8Twz&P-HsQAOF2t-7qouPDYi&)YYjI?BURCf@Vg3C#5H@?9s8 z^6+bC*Eb#Dm1E4@tbcE5q;ib%gP(K}z+$7^G4qf{I^*Vfj7VO^Hz2y)d86d%2(Nxb zN12B|={Hyn=Ow;cQI!#`8yFDR$An=qAol&fLBTF7>O|I$X!P*KP(T znO%ygv9+SKbK*zlN|O1dh?-9a1+Ck*%rHgNdi4_YvTd1TO1GU!2PLUxmMPP=OD?I? zJX5V%3F?_m-9#I*SFar@zo9bOI6mKg8+NNLSXya??N_FfHK*CUP7brW($~7}x_x#h z+AaW^>dy!Ozx&t!R6N*Sb!1bZmt_@oUiHx zM`^MWnf__8QSsK3NrLR#IGGP>QAKp9voxj2O6aYiVP;W1kqBzfb|~{jp(3R)Oz0+g zj2!T>d1ZrnMhBy&1LmKSz}HDe$K&B_6sBc5UEr@s^qCeC;U5vK(bPP+YRz6HuPH$W zJP&`bG&OVGBDrlY<aYZ~6aa!Pf;gPX}HBc|u8zx3$&s~@`6)tn8*e6{s)*&&iB9f^E4wsW4tlhB>O zbRg?gZTPCbgib%+nS^P^p)@g)=(g#r%QJZry3;t-(>z9XAZ7#G{U~= z0o_zkjJXL&Lw0TP8VI_4`{dfH14g9o0F4@8IgB{Ry0PmAo17B|hF9H-itGgUmK4WD zc$h&bvJv=_4v7PHfRw9v($j8!}`Jk~uUstw^)+|3)u?A!(YipL73%{kw zPhjvpFu!&Wq|_bEUzwZ~PVSC!_$YygZePO7W$;)4 zkCJ#O_R8Rc`CoN{P%;nGfdojeGRsVm)@(I|SO!*xI9r5~jC&c7FolfL5i%cx6{;kv zu8x@cBeCZClM)7zhQH?9C>sXN_YC(DlI`$q;n=%|@8}k)TP7;oxnz39k)#Vwe|UdS zt6)M`qb790sc&Mo^tx_b2b}xJ+f)^3>I?Z+2SjDVs@w~**MuF@7qf5|wqX?}&y(bKaq>;b(u7jGb4@jUuTyZPi~-9`QtQjhm{fF8 zaDMBn7V@mbdk(8`OQo!Ca8|SYw&ilFyj09|+w;{bGu+R037R}vatX>y+ITIq8;EF0 z{IF{RjQipEL+cDF&iJkNIQ~8#?1*E2>p=f_taFRUI?7egM@)&37rImLCH(7UMQIwL zpsWodRI|VI4w|WEfDKMw6rD_S#2=oVjZY>=n|~+{!$c^XLPlxN3hC2k(1mkOKiMD) z6se}ntV4TLgQ-*Icy=k$($UUBVCvmXrp+<}BldtoyWE4KTRuKMoHt3oZ>GR^*L|PLad0nBg(7#%+@;O65$AhJZz!S1Q zOT{h5K$PCcAn;nBi3MNNC@9WM%<$TVfet}S4}&L|9;2Yct;Hy$h4(QCVkVf7?KO=7 z^R@ONpo8AhL*R+;C(X!@fhfI?L69?H&7+_=Tl+B3ad!D(nB~0$A#pJmMCp%lDC2wZ zeQfE0z{Vm!5{{EjhxqJsh(YlatTsNh5a!yUU;a%$;to}~vPjc68~)f6|?z3*_31aO0w%Kt_sM5zy(qScDF7?K!w3%t=TwCzs4wmN*P z-n@OUjt)=Xx9d-ys9U}AU2owJ@kcGuS>1Nq{eHV6t|;?&yVvd=w0n5P_tvYC9;$WV z&YsZtCxP|@`e@VddVT4PJ~>mZ@It-r&X?XQP>njnt@LE3M}gXzdfs%V+f#4mET(O5 zHDz+w>&X+-ha1d~9Wx%t&58%F7lAw1JQ#b!$Otqh=HD$wY6m}e>dkt61WF+$LB?P8 z%AMS);Km8y!}W!RN2qXU@z;}yJ970RnBA%MayRgH$6$hXy>_LZvJnuveYBW(pf8|^ zYH##9YFAu6a~I}HvtCO9uhL?C11#Bv_&IYn1`!zPb($!8aJSUzeC5vFz`fP})rB|L zM~n4bxr?CR6RHt?KD>GT=Iw89ly%%w)v4D+=kvE0r|(aHJ<93aO>};9bn>jA^KKVe z23-+{x6W*>)!bS73iNEF->%;}D|9}=PblEk!kKF@7mU9oSwH&0%3Vyq)N8fQP^ldw z{{wXn}}GS+HHeKiURAhRm_GQIrLi zuL$4_W08^(1*X)YUas^AGs#eW@U1aH=mWxoA82RXHqK}@4_ZAo0%)gk`SJQL&@FX| zlb|WsD^ttL`HYlK{(X9mE<@wLbXux&kL;&{82aKGvJCj5AAm$*CX>Ne`#xl;3%m@y z-2dtq&gh1FlB&pYFT(bEZN2!k@IEh&T|FE7g3t%qUa!}v!!uwI1&x5|%YTS4q`2V@ zUi4etmbVOA7>AxtknWY!`os4Y{Nq`Ry7zY!whec}9v(z$JzoZQJO43g&%?QwfXkru z(rDKL?YR~0x|KzHp{_k|mVkmE0u4eg7`N5ybkcw$0rG?@06ek+Y75{oO1M8r;#pPNPpfny0FSMJ6AR!8Nti~oNjOLY zP6gnJ6>w?+JS_v9xEnp*AAr~Fr4e0$cxpv-Er_qwWac?(tqKui#Qikl9|G}}74Z)X z;_EWEA;f+UWIRYCeiDeUt%#p2h%apwfW>e6*{OIV0ACuw7UsUEm=N2RaGs1qH%WFN ze^Aoove{W_<@mlkT{zb>SP6KFqT<;Q>sNy-{a*N~M19c-5CKkIZn?-`A+Gz#@+xsg3#x z>Rflm*7;gR0|w~&U!F6Ts&1;MG3|U~;F2ILhUY%55KL)2cSB1@IxeihU_OGnjT#H8 zu!M=eYvq;iXeTr{EeauWly--T|cst4` zhUqG#Pqrg{x&`Ue?MS}@(qVN`s*zXQ(SB{%?)S=-{dzmnFM)KN)Z(3H6BHgGE-ITx@QQYdDlJRm@c1YAftp(S*xs_ej! zJbtJIiy1O{p{2OZ*i^qvoDuDYSUNPQ)JU!5L(_;Ay)jm3<*3jL7uADKW*In_>*_Nn zEO)6g)k;ovl^Vs<=~mFii>87cQ80XLQ~q3f(71A7<4krLub7a zg+36r@WADwq#n)(+oT1Tii^GMAZ?xL#e;yYqETdCasIu|~Kw?xgd4ueM@4j@CdjKiqu-N8pfMiK-Dfp{w1mqy# zUO-o4o!V5^(QFB;ceJ50Zh?B#Tn8weQ2{U{vMb zJ_jdtSvd(Ohkf5H9G!u%-1XsE2AMdX^$^{X`%>0i9QT(IjkcV!t8uE{i2&@O^ z^q^-UK$n0!1YlU)V}L#lrVBmlm=c8@5QY0=5W1kRC8mNqSp#kwsZuqn}Adpef`i)LP6P@m|1P zO6~!ZPBMoQY++0?tl^H7lgk{b9hf74Dkf#pN$x;`QsxlAxEf&^?pW`6sw3a8s5%4~ zFzM~N0|^Xsqyxj;bz(M14J?f_uGr1P0W029>mW&_Pp@6Ids- zYZ1VJN#}EiZdx2dejzV1+>z;Wxg(CYP#pn7d_xHsz(mdJ0ggP)Fh{}M%3N&ZEx2RS z)l^3|5V6R(9l4s}jsmikyJ(^nFqZ}xFlpkhPcFN)>d4)hIcLP7g2-8d9cdPhbpoed zGMY)8YD9c~*@{f&vYqrwa=W zSbUa=CmlyEYPTj=l7MHRn2V+lPa-pislQB_kzu7(5Ws|MPMq25h}31gn}CZU zIf+JK2q1lctLuJdmhO?@6~hBaU`qLG4tA^%ntOX3RY)NmSqJ=`RJTWcxTVXo(x)Mp zWeXp4gUWyhvvJ6C_SmHSoeXG78=*iZ+9igJdD(xMA!hV|0Z9ABL?^_=wx5uuNCI|K z;&e9P1`sv~OwyC^|v0SjIsBaFqZIkb=sI%Mi7$B>&A z2Cs@sC7fJjSn2e@76Fjf3}5u!Bo@gRdlc)J87gLrX_~?-)E98Eg}Mmdu*Iyf6HB%@ zTu1ssF^l{~lTl76*3jxfE zm&D&fT}-r$EmD!qy&`)UzDN}jUvSm1#c~i#wCKRG2*6w$Od|A+r3$bTRVpL_#Sn`GvPdCLON$gB z&5}i-69K*@b~0pCLqxnA1+onaGzbH-gG)=52nIqoO3;1iQUw5vbDJG6k!g*0%V4m5 zsR95|&?YZp7v#*$sg7har65fuGjV9fY_-LS0LJ1JDoiCRW@hnLCM*>3AUkgQ!V3c` zZri?Hz2NI?j4i zOo_yYpqHo7LOKcEvnH9J%l@$c5nmS*!0QbB_4V$|g?HQF3sUAfxbeoyTL;TEyz>Ht ztk)`zaTnEx=uMy(_`(|%>9HIq9z@^98hB$nU3T*1AvFt-@T9N1aOpYT()emR-t#*w z$^u77mhK84m)sW=51(=9AgvTo4HVWu9|Fav6ZqzM45_Ow+3<{p}akjZTW-iC?$}nAe=`M+PXdtDro;d4Skm!de_2AMyeBi&zD(OC$N)l7+FRqo|gJ~so zsOhimEd2*lOTt+wdHp|X24+&_i3G9bExt41x0SP8!mGyjuw9)!y;jhWHg#!_qurUQR?q;k8OwMEdYb zFZ{!mRjme%rWmC5LD+Z{rb=k07l2{U3%$B^N1A$4<2`mi;lj|6CE8^cHMJy;hL=0( z#aJ&!cc<{*28oxAHkA{O4y$5fiJ(hIM^!eC7lm+0q6|IEbTItBO}2#RL&?wuFYf|R f1y`YCIOYCsj0R&U 0 {") + { + g.P("src, err = fc.NextField(src)") + g.P("if err != nil { return ", fmtPackage.Ident("Errorf"), `("cannot read next field in %s", "`, msg.GoIdent.GoName, `")}`) + g.P("switch fc.FieldNum {") + { + for _, f := range msg.Fields { + g.P("case ", f.Desc.Number(), ":", " // ", f.GoName) + emitFieldUnmarshal(g, f) + } + } + g.P("}") + } + g.P("}") + + g.P("return nil") + g.P("}") +} + +func emitFieldUnmarshal(g *protogen.GeneratedFile, f *protogen.Field) { + name := castFieldName(f) + if f.Desc.Kind() == protoreflect.MessageKind { + g.P("data, ok := fc.MessageData()") + g.P(`if !ok { return fmt.Errorf("cannot unmarshal field %s", "`, f.GoName, `") }`) + if f.Desc.IsList() { + g.P(name, " = append(", name, ", ", fieldType(g, f)[2:], "{})") + g.P("ff := &", name, "[len(", name, ")-1]") + name = "ff" + } else if f.Oneof != nil { + const tmp = "oneofField" + g.P(tmp, " := &", f.GoIdent, "{", f.GoName, ": ", "new(", fieldType(g, f)[1:], ")}") + defer g.P(name, " = ", tmp) + + name = tmp + "." + f.GoName + } else { + g.P(name, " = new(", fieldType(g, f)[1:], ")") + } + + g.P(`if err := `, name, `.UnmarshalProtobuf(data); err != nil { return fmt.Errorf("unmarshal: %w", err)}`) + return + } + + getter, _ := easyprotoKindInfo(f.Desc.Kind()) + + if f.Desc.IsList() && (f.Desc.Kind() == protoreflect.BytesKind || f.Desc.Kind() == protoreflect.StringKind || f.Desc.Kind() == protoreflect.Uint64Kind && !f.Desc.IsPacked()) { + g.P("data, ok := fc.", getter, "()") + g.P(`if !ok { return fmt.Errorf("cannot unmarshal field %s", "`, f.GoName, `") }`) + g.P(name, " = append(", name, ", data)") + return + } + + if f.Desc.IsList() { + g.P("data, ok := fc.Unpack", getter, "s(nil)") + } else { + g.P("data, ok := fc.", getter, "()") + } + + g.P(`if !ok { return fmt.Errorf("cannot unmarshal field %s", "`, f.GoName, `") }`) + value := "data" + if f.Desc.Kind() == protoreflect.EnumKind { + value = fieldType(g, f).String() + "(data)" + } + + if f.Oneof == nil { + g.P("x.", f.GoName, " = ", value) + } else { + g.P("x.", f.Oneof.GoName, " = &", f.GoIdent, "{", f.GoName, ": data}") + } +} + +func emitMarshalProtobuf(g *protogen.GeneratedFile, msg *protogen.Message) { + g.P("// MarshalProtobuf implements the encoding.ProtoMarshaler interface.") + g.P("func (x *", msg.GoIdent.GoName, ") MarshalProtobuf(dst []byte) []byte {") + g.P("m := ", mp, ".Get()") + g.P("defer ", mp, ".Put(m)") + g.P("x.EmitProtobuf(m.MessageMarshaler())") + g.P("dst = m.Marshal(dst)") + g.P("return dst") + g.P("}\n") + + g.P("func (x *", msg.GoIdent.GoName, ") EmitProtobuf(mm *", easyprotoPackage.Ident("MessageMarshaler"), ") {") + if len(msg.Fields) != 0 { + fs := sortFields(msg.Fields) + + g.P("if x == nil { return }") + for _, f := range fs { + emitFieldMarshal(g, f) + } + } + g.P("}") +} + +func emitMarshalOneof(g *protogen.GeneratedFile, f *protogen.Field) { + name := "x." + f.Oneof.GoName + g.P("if inner, ok := ", name, ".(*", f.GoIdent.GoName, "); ok {") + defer g.P("}") + emitMarshalRaw(g, f, "inner."+f.GoName) +} + +// easyprotoKindInfo returns string name for kind, used in easyproto methods. +// The second return value is a condition to test for the default value of kind. +func easyprotoKindInfo(kind protoreflect.Kind) (string, func(string) string) { + switch kind { + case protoreflect.BoolKind: + return "Bool", identity + case protoreflect.EnumKind: + return "Int32", notZero + case protoreflect.Int32Kind: + return "Int32", notZero + case protoreflect.Sint32Kind: + return "Sint32", notZero + case protoreflect.Uint32Kind: + return "Uint32", notZero + case protoreflect.Int64Kind: + return "Int64", notZero + case protoreflect.Sint64Kind: + return "Sint64", notZero + case protoreflect.Uint64Kind: + return "Uint64", notZero + case protoreflect.Sfixed32Kind: + return "Sfixed32", notZero + case protoreflect.Fixed32Kind: + return "Fixed32", notZero + case protoreflect.FloatKind: + return "Float", notZero + case protoreflect.Sfixed64Kind: + return "Sfixed64", notZero + case protoreflect.Fixed64Kind: + return "Fixed64", notZero + case protoreflect.DoubleKind: + return "Double", notZero + case protoreflect.StringKind: + return "String", notEmpty + case protoreflect.BytesKind: + return "Bytes", notEmpty + case protoreflect.GroupKind: + panic("unimplemented") + default: + panic("unreachable") + } +} + +func emitFieldMarshal(g *protogen.GeneratedFile, f *protogen.Field) { + if f.Oneof != nil { + emitMarshalOneof(g, f) + return + } + + emitMarshalRaw(g, f, castFieldName(f)) +} + +func emitMarshalRaw(g *protogen.GeneratedFile, f *protogen.Field, name string) { + if f.Desc.Kind() == protoreflect.MessageKind { + if f.Desc.IsList() { + g.P("for i := range ", name, " {") + defer g.P("}") + + name += "[i]" + } else { + g.P("if ", notNil(name), " {") + defer g.P("}") + } + + g.P(name, ".EmitProtobuf(mm.AppendMessage(", f.Desc.Number(), "))") + return + } + + method, cond := easyprotoKindInfo(f.Desc.Kind()) + method = "Append" + method + if f.Desc.IsList() && !f.Desc.IsPacked() { + g.P("for j := range ", name, " {") + g.P("mm.", method, "(", f.Desc.Number(), ", ", name, "[j])") + g.P("}") + return + } + + if f.Desc.IsList() { + method += "s" + g.P("if ", notEmpty(name), "{") + } else { + g.P("if ", cond(name), " {") + } + + g.P("mm.", method, "(", f.Desc.Number(), ", ", name, ")") + g.P("}") +} diff --git a/api/util/protogen/internalgengo/proto_field_type.go b/api/util/protogen/internalgengo/proto_field_type.go new file mode 100644 index 0000000..0096751 --- /dev/null +++ b/api/util/protogen/internalgengo/proto_field_type.go @@ -0,0 +1,59 @@ +package internalgengo + +import ( + "google.golang.org/protobuf/compiler/protogen" + "google.golang.org/protobuf/reflect/protoreflect" +) + +type structField string + +func (f structField) String() string { + return string(f) +} + +func (f structField) PointerTo() structField { + return "*" + f +} + +func (f structField) SliceOf() structField { + return "[]" + f +} + +func fieldType(g *protogen.GeneratedFile, field *protogen.Field) structField { + var typ structField + switch field.Desc.Kind() { + case protoreflect.BoolKind: + typ = "bool" + case protoreflect.EnumKind: + typ = structField(g.QualifiedGoIdent(field.Enum.GoIdent)) + case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind: + typ = "int32" + case protoreflect.Uint32Kind, protoreflect.Fixed32Kind: + typ = "uint32" + case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind: + typ = "int64" + case protoreflect.Uint64Kind, protoreflect.Fixed64Kind: + typ = "uint64" + case protoreflect.FloatKind: + typ = "float32" + case protoreflect.DoubleKind: + typ = "float64" + case protoreflect.StringKind: + typ = "string" + case protoreflect.BytesKind: + typ = "[]byte" + case protoreflect.MessageKind: + typ = structField(g.QualifiedGoIdent(field.Message.GoIdent)) + if !field.Desc.IsList() { + typ = typ.PointerTo() + } + case protoreflect.GroupKind: + panic("unimplemented") + } + + if field.Desc.IsList() { + typ = "[]" + typ + } + + return typ +} diff --git a/api/util/protogen/internalgengo/proto_stable_compat.go b/api/util/protogen/internalgengo/proto_stable_compat.go new file mode 100644 index 0000000..3c4670c --- /dev/null +++ b/api/util/protogen/internalgengo/proto_stable_compat.go @@ -0,0 +1,124 @@ +package internalgengo + +import ( + "google.golang.org/protobuf/compiler/protogen" + "google.golang.org/protobuf/reflect/protoreflect" +) + +var protowirePackage = protogen.GoImportPath("google.golang.org/protobuf/encoding/protowire") + +func emitStableSize(g *protogen.GeneratedFile, msg *protogen.Message) { + fs := sortFields(msg.Fields) + + g.P("// StableSize returns the size of x in protobuf format.") + g.P("//") + g.P("// Structures with the same field values have the same binary size.") + g.P("func (x *", msg.GoIdent.GoName, ") StableSize() (size int) {") + g.P("if x == nil { return 0 }") + if len(fs) != 0 { + for _, f := range fs { + if f.Desc.IsList() && marshalers[f.Desc.Kind()].RepeatedDouble && !(f.Desc.Kind() == protoreflect.Uint64Kind && !f.Desc.IsPacked()) { + g.P("var n int") + break + } + } + for _, f := range fs { + emitFieldSize(g, f) + } + } + g.P("return size") + g.P("}\n") +} + +func emitSignatureMethods(g *protogen.GeneratedFile, msg *protogen.Message) { + // SignedDataSize implementation (only for requests and responses). + g.P("// ReadSignedData fills buf with signed data of x.") + g.P("// If buffer length is less than x.SignedDataSize(), new buffer is allocated.") + g.P("//") + g.P("// Returns any error encountered which did not allow writing the data completely.") + g.P("// Otherwise, returns the buffer in which the data is written.") + g.P("//") + g.P("// Structures with the same field values have the same signed data.") + g.P("func (x *", msg.GoIdent.GoName, ") SignedDataSize() int {") + g.P("return x.GetBody().StableSize()") + g.P("}\n") + + // ReadSignedData implementation (only for requests and responses). + g.P("// SignedDataSize returns size of the request signed data in bytes.") + g.P("//") + g.P("// Structures with the same field values have the same signed data size.") + g.P("func (x *", msg.GoIdent.GoName, ") ReadSignedData(buf []byte) ([]byte, error) {") + g.P("return x.GetBody().MarshalProtobuf(buf), nil") + g.P("}\n") +} + +func emitFieldSize(g *protogen.GeneratedFile, f *protogen.Field) { + m := marshalers[f.Desc.Kind()] + if m.Prefix == "" { + g.P("// FIXME missing field marshaler: ", f.GoName, " of type ", f.Desc.Kind().String()) + g.P(`panic("unimplemented")`) + return + } + + name := castFieldName(f) + if f.Oneof != nil { + name = "x." + f.Oneof.GoName + g.P("if inner, ok := ", name, ".(*", f.GoIdent.GoName, "); ok {") + defer g.P("}") + name = "inner." + f.GoName + } + + switch { + case f.Desc.IsList() && (f.Desc.Kind() == protoreflect.MessageKind || f.Desc.Kind() == protoreflect.Uint64Kind && !f.Desc.IsPacked()): + g.P("for i := range ", name, "{") + if f.Desc.Kind() == protoreflect.MessageKind { + g.P("size += ", protoPackage.Ident("NestedStructureSizeUnchecked"), "(", f.Desc.Number(), ", &", name, "[i])") + } else { + if f.Desc.Kind() != protoreflect.Uint64Kind { + panic("only uint64 unpacked primitive is supported") + } + + g.P("size += ", protowirePackage.Ident("SizeGroup"), "(", + protowirePackage.Ident("Number"), "(", f.Desc.Number(), "), ", + protowirePackage.Ident("SizeVarint"), "(", name, "[i]))") + } + g.P("}") + + case f.Desc.IsList(): + if m.RepeatedDouble { + g.P("n, _ = ", protoPackage.Ident("Repeated"+m.Prefix+"Size"), "(", f.Desc.Number(), ", ", name, ")") + g.P("size += n") + } else { + g.P("size += ", protoPackage.Ident("Repeated"+m.Prefix+"Size"), "(", f.Desc.Number(), ", ", name, ")") + } + default: + g.P("size += ", protoPackage.Ident(m.Prefix+"Size"), "(", f.Desc.Number(), ", ", name, ")") + } +} + +type marshalerDesc struct { + Prefix string + RepeatedDouble bool +} + +// Unused kinds are commented. +var marshalers = map[protoreflect.Kind]marshalerDesc{ + protoreflect.BoolKind: {Prefix: "Bool"}, + protoreflect.EnumKind: {Prefix: "Enum"}, + protoreflect.Int32Kind: {Prefix: "Int32", RepeatedDouble: true}, + // protoreflect.Sint32Kind: "", + protoreflect.Uint32Kind: {Prefix: "UInt32", RepeatedDouble: true}, + protoreflect.Int64Kind: {Prefix: "Int64", RepeatedDouble: true}, + // protoreflect.Sint64Kind: "", + protoreflect.Uint64Kind: {Prefix: "UInt64", RepeatedDouble: true}, + // protoreflect.Sfixed32Kind: "", + protoreflect.Fixed32Kind: {Prefix: "Fixed32", RepeatedDouble: true}, + // protoreflect.FloatKind: "", + // protoreflect.Sfixed64Kind: "", + protoreflect.Fixed64Kind: {Prefix: "Fixed64", RepeatedDouble: true}, + protoreflect.DoubleKind: {Prefix: "Float64"}, + protoreflect.StringKind: {Prefix: "String"}, + protoreflect.BytesKind: {Prefix: "Bytes"}, + protoreflect.MessageKind: {Prefix: "NestedStructure"}, + // protoreflect.GroupKind: "", +} diff --git a/api/util/protogen/internalgengo/writer.go b/api/util/protogen/internalgengo/writer.go new file mode 100644 index 0000000..7b0d4f1 --- /dev/null +++ b/api/util/protogen/internalgengo/writer.go @@ -0,0 +1,30 @@ +package internalgengo + +import ( + "fmt" +) + +type condition = func(string) string + +var ( + _ condition = notZero + _ condition = notEmpty + _ condition = identity + _ condition = notNil +) + +func notZero(name string) string { + return fmt.Sprintf("%s != 0", name) +} + +func notEmpty(name string) string { + return fmt.Sprintf("len(%s) != 0", name) +} + +func identity(name string) string { + return name +} + +func notNil(name string) string { + return fmt.Sprintf("%s != nil", name) +} diff --git a/api/util/protogen/main.go b/api/util/protogen/main.go new file mode 100644 index 0000000..3ebc1dd --- /dev/null +++ b/api/util/protogen/main.go @@ -0,0 +1,27 @@ +package main + +import ( + "flag" + + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/util/protogen/internalgengo" + "google.golang.org/protobuf/compiler/protogen" +) + +func main() { + var flags flag.FlagSet + genFuzz := flags.Bool("fuzz", false, "generate fuzz tests") + + protogen.Options{ + ParamFunc: flags.Set, + }.Run(func(gen *protogen.Plugin) error { + for _, f := range gen.Files { + if f.Generate { + internalgengo.GenerateFile(gen, f) + if *genFuzz { + internalgengo.GenerateFuzzTests(gen, f) + } + } + } + return nil + }) +} diff --git a/api/util/signature/data.go b/api/util/signature/data.go new file mode 100644 index 0000000..e444a73 --- /dev/null +++ b/api/util/signature/data.go @@ -0,0 +1,93 @@ +package signature + +import ( + "crypto/ecdsa" + + crypto "git.frostfs.info/TrueCloudLab/frostfs-crypto" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/util/pool" +) + +const poolSliceMaxSize = 128 * 1024 + +var buffersPool = pool.NewBufferPool(poolSliceMaxSize) + +type DataSource interface { + ReadSignedData([]byte) ([]byte, error) + SignedDataSize() int +} + +type DataWithSignature interface { + DataSource + GetSignature() *refs.Signature + SetSignature(*refs.Signature) +} + +type SignOption func(*cfg) + +type KeySignatureHandler func(*refs.Signature) + +type KeySignatureSource func() *refs.Signature + +func SignDataWithHandler(key *ecdsa.PrivateKey, src DataSource, handler KeySignatureHandler, opts ...SignOption) error { + if key == nil { + return crypto.ErrEmptyPrivateKey + } + + cfg := defaultCfg() + + for i := range opts { + opts[i](cfg) + } + + buffer := buffersPool.Get(uint32(src.SignedDataSize())) + defer buffersPool.Put(buffer) + + data, err := src.ReadSignedData(buffer.Data) + if err != nil { + return err + } + + sigData, err := sign(cfg, key, data) + if err != nil { + return err + } + + sig := new(refs.Signature) + sig.SetScheme(cfg.scheme) + sig.SetKey(crypto.MarshalPublicKey(&key.PublicKey)) + sig.SetSign(sigData) + handler(sig) + + return nil +} + +func VerifyDataWithSource(dataSrc DataSource, sigSrc KeySignatureSource, opts ...SignOption) error { + buffer := buffersPool.Get(uint32(dataSrc.SignedDataSize())) + defer buffersPool.Put(buffer) + + data, err := dataSrc.ReadSignedData(buffer.Data) + if err != nil { + return err + } + + return VerifyDataSlice(data, sigSrc, opts...) +} + +func SignData(key *ecdsa.PrivateKey, v DataWithSignature, opts ...SignOption) error { + return SignDataWithHandler(key, v, v.SetSignature, opts...) +} + +func VerifyData(src DataWithSignature, opts ...SignOption) error { + return VerifyDataWithSource(src, src.GetSignature, opts...) +} + +func VerifyDataSlice(data []byte, sigSrc KeySignatureSource, opts ...SignOption) error { + cfg := defaultCfg() + + for i := range opts { + opts[i](cfg) + } + + return verify(cfg, data, sigSrc()) +} diff --git a/api/util/signature/options.go b/api/util/signature/options.go new file mode 100644 index 0000000..d27eff2 --- /dev/null +++ b/api/util/signature/options.go @@ -0,0 +1,77 @@ +package signature + +import ( + "crypto/ecdsa" + "encoding/base64" + "fmt" + + crypto "git.frostfs.info/TrueCloudLab/frostfs-crypto" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/util/signature/walletconnect" +) + +type cfg struct { + schemeFixed bool + scheme refs.SignatureScheme +} + +func defaultCfg() *cfg { + return new(cfg) +} + +func verify(cfg *cfg, data []byte, sig *refs.Signature) error { + if !cfg.schemeFixed { + cfg.scheme = sig.GetScheme() + } + + pub := crypto.UnmarshalPublicKey(sig.GetKey()) + if pub == nil { + return crypto.ErrEmptyPublicKey + } + + switch cfg.scheme { + case refs.ECDSA_SHA512: + return crypto.Verify(pub, data, sig.GetSign()) + case refs.ECDSA_RFC6979_SHA256: + return crypto.VerifyRFC6979(pub, data, sig.GetSign()) + case refs.ECDSA_RFC6979_SHA256_WALLET_CONNECT: + buffer := buffersPool.Get(uint32(base64.StdEncoding.EncodedLen(len(data)))) + defer buffersPool.Put(buffer) + base64.StdEncoding.Encode(buffer.Data, data) + if !walletconnect.Verify(pub, buffer.Data, sig.GetSign()) { + return crypto.ErrInvalidSignature + } + return nil + default: + return fmt.Errorf("unsupported signature scheme %s", cfg.scheme) + } +} + +func sign(cfg *cfg, key *ecdsa.PrivateKey, data []byte) ([]byte, error) { + switch cfg.scheme { + case refs.ECDSA_SHA512: + return crypto.Sign(key, data) + case refs.ECDSA_RFC6979_SHA256: + return crypto.SignRFC6979(key, data) + case refs.ECDSA_RFC6979_SHA256_WALLET_CONNECT: + buffer := buffersPool.Get(uint32(base64.StdEncoding.EncodedLen(len(data)))) + defer buffersPool.Put(buffer) + base64.StdEncoding.Encode(buffer.Data, data) + return walletconnect.Sign(key, buffer.Data) + default: + panic(fmt.Sprintf("unsupported scheme %s", cfg.scheme)) + } +} + +func SignWithRFC6979() SignOption { + return func(c *cfg) { + c.schemeFixed = true + c.scheme = refs.ECDSA_RFC6979_SHA256 + } +} + +func SignWithWalletConnect() SignOption { + return func(c *cfg) { + c.scheme = refs.ECDSA_RFC6979_SHA256_WALLET_CONNECT + } +} diff --git a/api/util/signature/sign_test.go b/api/util/signature/sign_test.go new file mode 100644 index 0000000..222f9be --- /dev/null +++ b/api/util/signature/sign_test.go @@ -0,0 +1,44 @@ +package signature + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "testing" + + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + "github.com/stretchr/testify/require" +) + +type testData struct { + data []byte + sig *refs.Signature +} + +func (t testData) SignedDataSize() int { return len(t.data) } +func (t testData) ReadSignedData(data []byte) ([]byte, error) { + n := copy(data, t.data) + return data[:n], nil +} +func (t testData) GetSignature() *refs.Signature { return t.sig } +func (t *testData) SetSignature(s *refs.Signature) { t.sig = s } + +func TestWalletConnect(t *testing.T) { + testCases := [...][]byte{ + {}, + {0}, + {1, 2}, + {3, 4, 5}, + {6, 7, 8, 9, 10, 11, 12}, + } + + pk, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + require.NoError(t, err) + + for _, tc := range testCases { + td := &testData{data: tc} + require.NoError(t, SignData(pk, td, SignWithWalletConnect())) + require.Equal(t, refs.ECDSA_RFC6979_SHA256_WALLET_CONNECT, td.sig.GetScheme()) + require.NoError(t, VerifyData(td)) + } +} diff --git a/api/util/signature/walletconnect/sign.go b/api/util/signature/walletconnect/sign.go new file mode 100644 index 0000000..b96a842 --- /dev/null +++ b/api/util/signature/walletconnect/sign.go @@ -0,0 +1,142 @@ +package walletconnect + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "encoding/binary" + "encoding/hex" + + crypto "git.frostfs.info/TrueCloudLab/frostfs-crypto" +) + +const ( + // saltSize is the salt size added to signed message. + saltSize = 16 + // signatureLen is the length of RFC6979 signature. + signatureLen = 64 +) + +// SignedMessage contains mirrors `SignedMessage` struct from the WalletConnect API. +// https://neon.coz.io/wksdk/core/modules.html#SignedMessage +type SignedMessage struct { + Data []byte + Message []byte + PublicKey []byte + Salt []byte +} + +// Sign signs message using WalletConnect API. The returned signature +// contains RFC6979 signature and 16-byte salt. +func Sign(p *ecdsa.PrivateKey, msg []byte) ([]byte, error) { + sm, err := SignMessage(p, msg) + if err != nil { + return nil, err + } + return append(sm.Data, sm.Salt...), nil +} + +// Verify verifies message using WalletConnect API. +func Verify(p *ecdsa.PublicKey, data, sign []byte) bool { + if len(sign) != signatureLen+saltSize { + return false + } + + salt := sign[signatureLen:] + return VerifyMessage(p, SignedMessage{ + Data: sign[:signatureLen], + Message: createMessageWithSalt(data, salt), + Salt: salt, + }) +} + +// SignMessage signs message with a private key and returns structure similar to +// `signMessage` of the WalletConnect API. +// https://github.com/CityOfZion/wallet-connect-sdk/blob/89c236b/packages/wallet-connect-sdk-core/src/index.ts#L496 +// https://github.com/CityOfZion/neon-wallet/blob/1174a9388480e6bbc4f79eb13183c2a573f67ca8/app/context/WalletConnect/helpers.js#L133 +func SignMessage(p *ecdsa.PrivateKey, msg []byte) (SignedMessage, error) { + var salt [saltSize]byte + _, _ = rand.Read(salt[:]) + + msg = createMessageWithSalt(msg, salt[:]) + sign, err := crypto.SignRFC6979(p, msg) + if err != nil { + return SignedMessage{}, err + } + + return SignedMessage{ + Data: sign, + Message: msg, + PublicKey: elliptic.MarshalCompressed(p.Curve, p.X, p.Y), + Salt: salt[:], + }, nil +} + +// VerifyMessage verifies message with a private key and returns structure similar to +// `verifyMessage` of WalletConnect API. +// https://github.com/CityOfZion/wallet-connect-sdk/blob/89c236b/packages/wallet-connect-sdk-core/src/index.ts#L515 +// https://github.com/CityOfZion/neon-wallet/blob/1174a9388480e6bbc4f79eb13183c2a573f67ca8/app/context/WalletConnect/helpers.js#L147 +func VerifyMessage(p *ecdsa.PublicKey, m SignedMessage) bool { + if p == nil { + x, y := elliptic.UnmarshalCompressed(elliptic.P256(), m.PublicKey) + if x == nil || y == nil { + return false + } + p = &ecdsa.PublicKey{ + Curve: elliptic.P256(), + X: x, + Y: y, + } + } + return crypto.VerifyRFC6979(p, m.Message, m.Data) == nil +} + +func createMessageWithSalt(msg, salt []byte) []byte { + // 4 byte prefix + length of the message with salt in bytes + + // + salt + message + 2 byte postfix. + saltedLen := hex.EncodedLen(len(salt)) + len(msg) + data := make([]byte, 4+getVarIntSize(saltedLen)+saltedLen+2) + + n := copy(data, []byte{0x01, 0x00, 0x01, 0xf0}) // fixed prefix + n += putVarUint(data[n:], uint64(saltedLen)) // salt is hex encoded, double its size + n += hex.Encode(data[n:], salt[:]) // for some reason we encode salt in hex + n += copy(data[n:], msg) + copy(data[n:], []byte{0x00, 0x00}) + + return data +} + +// Following functions are copied from github.com/nspcc-dev/neo-go/pkg/io package +// to avoid having another dependency. + +// getVarIntSize returns the size in number of bytes of a variable integer. +// Reference: https://github.com/neo-project/neo/blob/26d04a642ac5a1dd1827dabf5602767e0acba25c/src/neo/IO/Helper.cs#L131 +func getVarIntSize(value int) int { + var size uintptr + + if value < 0xFD { + size = 1 // unit8 + } else if value <= 0xFFFF { + size = 3 // byte + uint16 + } else { + size = 5 // byte + uint32 + } + return int(size) +} + +// putVarUint puts val in varint form to the pre-allocated buffer. +func putVarUint(data []byte, val uint64) int { + if val < 0xfd { + data[0] = byte(val) + return 1 + } + if val <= 0xFFFF { + data[0] = byte(0xfd) + binary.LittleEndian.PutUint16(data[1:], uint16(val)) + return 3 + } + + data[0] = byte(0xfe) + binary.LittleEndian.PutUint32(data[1:], uint32(val)) + return 5 +} diff --git a/api/util/signature/walletconnect/sign_test.go b/api/util/signature/walletconnect/sign_test.go new file mode 100644 index 0000000..1b4fe18 --- /dev/null +++ b/api/util/signature/walletconnect/sign_test.go @@ -0,0 +1,112 @@ +package walletconnect + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" + "encoding/hex" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestSignMessage(t *testing.T) { + p1, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + require.NoError(t, err) + + msg := []byte("NEO") + result, err := SignMessage(p1, msg) + require.NoError(t, err) + require.Equal(t, elliptic.MarshalCompressed(elliptic.P256(), p1.PublicKey.X, p1.PublicKey.Y), result.PublicKey) + require.Equal(t, saltSize, len(result.Salt)) + require.Equal(t, 64, len(result.Data)) + require.Equal(t, 4+1+16*2+3+2, len(result.Message)) + + require.True(t, VerifyMessage(&p1.PublicKey, result)) + + t.Run("invalid public key", func(t *testing.T) { + p2, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + require.NoError(t, err) + require.False(t, VerifyMessage(&p2.PublicKey, result)) + }) + t.Run("invalid signature", func(t *testing.T) { + result := result + result.Data[0] ^= 0xFF + require.False(t, VerifyMessage(&p1.PublicKey, result)) + }) +} + +func TestSign(t *testing.T) { + p1, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + require.NoError(t, err) + + msg := []byte("NEO") + sign, err := Sign(p1, msg) + require.NoError(t, err) + require.True(t, Verify(&p1.PublicKey, msg, sign)) + + t.Run("invalid public key", func(t *testing.T) { + p2, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + require.NoError(t, err) + require.False(t, Verify(&p2.PublicKey, msg, sign)) + }) + t.Run("invalid signature", func(t *testing.T) { + sign[0] ^= 0xFF + require.False(t, Verify(&p1.PublicKey, msg, sign)) + }) +} + +func TestVerifyNeonWallet(t *testing.T) { + testCases := [...]struct { + publicKey string + data string + salt string + messageHex string + messageOriginal string + }{ + { // Test values from this GIF https://github.com/CityOfZion/neon-wallet/pull/2390 . + publicKey: "02ce6228ba2cb2fc235be93aff9cd5fc0851702eb9791552f60db062f01e3d83f6", + data: "90ab1886ca0bece59b982d9ade8f5598065d651362fb9ce45ad66d0474b89c0b80913c8f0118a282acbdf200a429ba2d81bc52534a53ab41a2c6dfe2f0b4fb1b", + salt: "d41e348afccc2f3ee45cd9f5128b16dc", + messageHex: "010001f05c6434316533343861666363633266336565343563643966353132386231366463436172616c686f2c206d756c65712c206f2062616775697520656820697373756d65726d6f2074616978206c696761646f206e61206d697373e36f3f0000", + messageOriginal: "436172616c686f2c206d756c65712c206f2062616775697520656820697373756d65726d6f2074616978206c696761646f206e61206d697373e36f3f", + }, + { // Test value from wallet connect integration test + publicKey: "03bd9108c0b49f657e9eee50d1399022bd1e436118e5b7529a1b7cd606652f578f", + data: "510caa8cb6db5dedf04d215a064208d64be7496916d890df59aee132db8f2b07532e06f7ea664c4a99e3bcb74b43a35eb9653891b5f8701d2aef9e7526703eaa", + salt: "2c5b189569e92cce12e1c640f23e83ba", + messageHex: "010001f02632633562313839353639653932636365313265316336343066323365383362613132333435360000", + messageOriginal: "313233343536", // ascii string "123456" + }, + { // Test value from wallet connect integration test + publicKey: "03bd9108c0b49f657e9eee50d1399022bd1e436118e5b7529a1b7cd606652f578f", + data: "1e13f248962d8b3b60708b55ddf448d6d6a28c6b43887212a38b00bf6bab695e61261e54451c6e3d5f1f000e5534d166c7ca30f662a296d3a9aafa6d8c173c01", + salt: "58c86b2e74215b4f36b47d731236be3b", + messageHex: "010001f02035386338366232653734323135623466333662343764373331323336626533620000", + messageOriginal: "", // empty string + }, + } + + for _, testCase := range testCases { + rawPub, err := hex.DecodeString(testCase.publicKey) + require.NoError(t, err) + data, err := hex.DecodeString(testCase.data) + require.NoError(t, err) + salt, err := hex.DecodeString(testCase.salt) + require.NoError(t, err) + msg, err := hex.DecodeString(testCase.messageHex) + require.NoError(t, err) + orig, err := hex.DecodeString(testCase.messageOriginal) + require.NoError(t, err) + + require.Equal(t, msg, createMessageWithSalt(orig, salt)) + + sm := SignedMessage{ + Data: data, + Message: msg, + PublicKey: rawPub, + Salt: salt, + } + require.True(t, VerifyMessage(nil, sm)) + } +} diff --git a/bearer/bearer.go b/bearer/bearer.go index e419d54..d1b77ed 100644 --- a/bearer/bearer.go +++ b/bearer/bearer.go @@ -5,10 +5,10 @@ import ( "errors" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" - apeV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/ape" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" apeSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" + apeV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/ape" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa" @@ -18,7 +18,7 @@ import ( // Token represents bearer token for object service operations. // -// Token is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl.BearerToken +// Token is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl.BearerToken // message. See ReadFromV2 / WriteToV2 methods. // // Instances can be created using built-in var declaration. diff --git a/bearer/bearer_test.go b/bearer/bearer_test.go index 341c4f2..650dc82 100644 --- a/bearer/bearer_test.go +++ b/bearer/bearer_test.go @@ -6,8 +6,8 @@ import ( "reflect" "testing" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer" bearertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer/test" cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test" diff --git a/checksum/checksum.go b/checksum/checksum.go index 9d227ad..76887f6 100644 --- a/checksum/checksum.go +++ b/checksum/checksum.go @@ -6,13 +6,13 @@ import ( "errors" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" "git.frostfs.info/TrueCloudLab/tzhash/tz" ) // Checksum represents checksum of some digital data. // -// Checksum is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs.Checksum +// Checksum is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs.Checksum // message. See ReadFromV2 / WriteToV2 methods. // // Instances can be created using built-in var declaration. diff --git a/checksum/checksum_test.go b/checksum/checksum_test.go index 9da857d..1e1c07c 100644 --- a/checksum/checksum_test.go +++ b/checksum/checksum_test.go @@ -5,7 +5,7 @@ import ( "crypto/sha256" "testing" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" "git.frostfs.info/TrueCloudLab/tzhash/tz" "github.com/stretchr/testify/require" ) diff --git a/checksum/example_test.go b/checksum/example_test.go index 337767a..72d4a05 100644 --- a/checksum/example_test.go +++ b/checksum/example_test.go @@ -6,7 +6,7 @@ import ( "crypto/sha256" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" ) func ExampleCalculate() { diff --git a/client/accounting.go b/client/accounting.go index faf7ddc..707ec3d 100644 --- a/client/accounting.go +++ b/client/accounting.go @@ -4,13 +4,13 @@ import ( "context" "fmt" - v2accounting "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/accounting" + v2accounting "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/accounting" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + rpcapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + v2session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" ) diff --git a/client/apemanager_add_chain.go b/client/apemanager_add_chain.go index 2581e2a..a8d53a7 100644 --- a/client/apemanager_add_chain.go +++ b/client/apemanager_add_chain.go @@ -4,12 +4,12 @@ import ( "context" "fmt" - apemanagerV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/apemanager" - rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - sessionV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" apeSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape" + apemanagerV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/apemanager" + rpcapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + sessionV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" ) diff --git a/client/apemanager_list_chains.go b/client/apemanager_list_chains.go index a8a3e8a..56cc4ef 100644 --- a/client/apemanager_list_chains.go +++ b/client/apemanager_list_chains.go @@ -4,12 +4,12 @@ import ( "context" "fmt" - apemanagerV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/apemanager" - rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - sessionV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" apeSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape" + apemanagerV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/apemanager" + rpcapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + sessionV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" ) diff --git a/client/apemanager_remove_chain.go b/client/apemanager_remove_chain.go index a297716..39ccdeb 100644 --- a/client/apemanager_remove_chain.go +++ b/client/apemanager_remove_chain.go @@ -4,12 +4,12 @@ import ( "context" "fmt" - apemanagerV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/apemanager" - rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - sessionV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" apeSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ape" + apemanagerV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/apemanager" + rpcapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + sessionV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" ) diff --git a/client/api.go b/client/api.go index dd18c42..c86dde2 100644 --- a/client/api.go +++ b/client/api.go @@ -4,9 +4,9 @@ import ( "context" "fmt" - v2netmap "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap" - rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" + v2netmap "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/netmap" + rpcapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" ) // interface of FrostFS API server. Exists for test purposes only. diff --git a/client/client.go b/client/client.go index 0894f0e..98d4275 100644 --- a/client/client.go +++ b/client/client.go @@ -7,9 +7,9 @@ import ( "errors" "time" - v2accounting "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" + v2accounting "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/accounting" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" "google.golang.org/grpc" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -129,7 +129,7 @@ func (c *Client) Dial(ctx context.Context, prm PrmDial) error { // sets underlying provider of frostFSAPIServer. The method is used for testing as an approach // to skip Dial stage and override FrostFS API server. MUST NOT be used outside test code. -// In real applications wrapper over git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client +// In real applications wrapper over git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client // is statically used. func (c *Client) setFrostFSAPIServer(server frostFSAPIServer) { c.server = server diff --git a/client/common.go b/client/common.go index 65abae5..ba8281d 100644 --- a/client/common.go +++ b/client/common.go @@ -4,10 +4,10 @@ import ( "errors" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + v2session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version" ) @@ -104,7 +104,7 @@ func (c *Client) processResponse(resp responseV2) (apistatus.Status, error) { return st, nil } -// ExecRaw executes f with underlying git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client.Client +// ExecRaw executes f with underlying sdk-go/api/rpc/client.Client // instance. Communicate over the Protocol Buffers protocol in a more flexible way: // most often used to transmit data over a fixed version of the FrostFS protocol, as well // as to support custom services. @@ -115,7 +115,7 @@ func (c *Client) processResponse(resp responseV2) (apistatus.Status, error) { // before closing the connection. // // See also Dial and Close. -// See also git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client package docs. +// See also git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client package docs. func (c *Client) ExecRaw(f func(client *client.Client) error) error { return f(&c.c) } diff --git a/client/container_delete.go b/client/container_delete.go index 6d4b345..cf5adf4 100644 --- a/client/container_delete.go +++ b/client/container_delete.go @@ -4,12 +4,12 @@ import ( "context" "fmt" - v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" + v2container "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + rpcapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + v2session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa" diff --git a/client/container_get.go b/client/container_get.go index da8166f..fd34090 100644 --- a/client/container_get.go +++ b/client/container_get.go @@ -5,12 +5,12 @@ import ( "errors" "fmt" - v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" + v2container "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + rpcapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + v2session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" diff --git a/client/container_list.go b/client/container_list.go index 6d2efb6..d094cdb 100644 --- a/client/container_list.go +++ b/client/container_list.go @@ -4,12 +4,12 @@ import ( "context" "fmt" - v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" + v2container "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + rpcapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + v2session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session" diff --git a/client/container_put.go b/client/container_put.go index e5b8f18..30ebf7a 100644 --- a/client/container_put.go +++ b/client/container_put.go @@ -4,12 +4,12 @@ import ( "context" "fmt" - v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" + v2container "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + rpcapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + v2session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" diff --git a/client/doc.go b/client/doc.go index 7f6ec42..2a1d607 100644 --- a/client/doc.go +++ b/client/doc.go @@ -47,8 +47,8 @@ Consume custom service of the server: rpc CustomRPC(CustomRPCRequest) returns (CustomRPCResponse); } - import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/common" + import "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + import "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/common" req := new(CustomRPCRequest) // ... diff --git a/client/netmap.go b/client/netmap.go index a870ab2..f87d3b0 100644 --- a/client/netmap.go +++ b/client/netmap.go @@ -4,11 +4,11 @@ import ( "context" "fmt" - v2netmap "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap" - rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" + v2netmap "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/netmap" + rpcapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + v2session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version" diff --git a/client/netmap_test.go b/client/netmap_test.go index bce6b3a..d6ff0fb 100644 --- a/client/netmap_test.go +++ b/client/netmap_test.go @@ -6,9 +6,9 @@ import ( "fmt" "testing" - v2netmap "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" + v2netmap "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/netmap" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap" "github.com/stretchr/testify/require" diff --git a/client/object_delete.go b/client/object_delete.go index 3214cff..048398c 100644 --- a/client/object_delete.go +++ b/client/object_delete.go @@ -5,13 +5,13 @@ import ( "crypto/ecdsa" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" - v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" - v2refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" + v2object "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object" + v2refs "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + rpcapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + v2session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" diff --git a/client/object_get.go b/client/object_get.go index ba4f72d..b84844e 100644 --- a/client/object_get.go +++ b/client/object_get.go @@ -7,13 +7,13 @@ import ( "fmt" "io" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" - v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" - v2refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" + v2object "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object" + v2refs "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + rpcapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + v2session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" diff --git a/client/object_hash.go b/client/object_hash.go index b1b9ffc..83f2360 100644 --- a/client/object_hash.go +++ b/client/object_hash.go @@ -5,13 +5,13 @@ import ( "crypto/ecdsa" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" - v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" - v2refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" + v2object "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object" + v2refs "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + rpcapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + v2session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" diff --git a/client/object_patch.go b/client/object_patch.go index 7b054db..6930644 100644 --- a/client/object_patch.go +++ b/client/object_patch.go @@ -7,12 +7,12 @@ import ( "fmt" "io" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" - v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" - rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" + v2object "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object" + rpcapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + v2session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" diff --git a/client/object_patch_test.go b/client/object_patch_test.go index 839c453..63996b6 100644 --- a/client/object_patch_test.go +++ b/client/object_patch_test.go @@ -8,7 +8,7 @@ import ( "crypto/rand" "testing" - v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" + v2object "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test" "github.com/stretchr/testify/require" diff --git a/client/object_put.go b/client/object_put.go index 07ca840..9a01f34 100644 --- a/client/object_put.go +++ b/client/object_put.go @@ -4,7 +4,7 @@ import ( "context" "crypto/ecdsa" - buffPool "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/pool" + buffPool "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/util/pool" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" diff --git a/client/object_put_raw.go b/client/object_put_raw.go index e47c6a2..b682102 100644 --- a/client/object_put_raw.go +++ b/client/object_put_raw.go @@ -7,12 +7,12 @@ import ( "fmt" "io" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" - v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" - rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" + v2object "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object" + rpcapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + v2session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" ) diff --git a/client/object_put_single.go b/client/object_put_single.go index a2ff8a0..ffce126 100644 --- a/client/object_put_single.go +++ b/client/object_put_single.go @@ -5,12 +5,12 @@ import ( "crypto/ecdsa" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" - v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" - rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" + v2object "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object" + rpcapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + v2session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session" diff --git a/client/object_put_transformer.go b/client/object_put_transformer.go index 5314a12..7e30be1 100644 --- a/client/object_put_transformer.go +++ b/client/object_put_transformer.go @@ -3,7 +3,7 @@ package client import ( "context" - buffPool "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/pool" + buffPool "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/util/pool" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/transformer" diff --git a/client/object_search.go b/client/object_search.go index 42018e5..781d872 100644 --- a/client/object_search.go +++ b/client/object_search.go @@ -7,13 +7,13 @@ import ( "fmt" "io" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" - v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" - v2refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" + v2object "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object" + v2refs "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + rpcapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + v2session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" diff --git a/client/object_search_test.go b/client/object_search_test.go index f449d61..f385f48 100644 --- a/client/object_search_test.go +++ b/client/object_search_test.go @@ -7,9 +7,9 @@ import ( "io" "testing" - v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - signatureV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" + v2object "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + signatureV2 "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" diff --git a/client/response.go b/client/response.go index e1a702e..69972b9 100644 --- a/client/response.go +++ b/client/response.go @@ -1,6 +1,6 @@ package client -import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" +import "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" // ResponseMetaInfo groups meta information about any FrostFS API response. type ResponseMetaInfo struct { diff --git a/client/session.go b/client/session.go index b49c67b..9f806f0 100644 --- a/client/session.go +++ b/client/session.go @@ -5,11 +5,11 @@ import ( "crypto/ecdsa" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + rpcapi "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/rpc/client" + v2session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/signature" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" ) diff --git a/client/status/apemanager.go b/client/status/apemanager.go index f68fd48..b4d49cb 100644 --- a/client/status/apemanager.go +++ b/client/status/apemanager.go @@ -1,8 +1,8 @@ package apistatus import ( - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/apemanager" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/apemanager" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status" ) // APEManagerAccessDenied describes status of the failure because of the access control violation. diff --git a/client/status/common.go b/client/status/common.go index 598631b..486bc72 100644 --- a/client/status/common.go +++ b/client/status/common.go @@ -3,7 +3,7 @@ package apistatus import ( "encoding/binary" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status" ) // ServerInternal describes failure statuses related to internal server errors. @@ -53,7 +53,7 @@ func (x ServerInternal) Message() string { // WriteInternalServerErr writes err message to ServerInternal instance. func WriteInternalServerErr(x *ServerInternal, err error) { - x.SetMessage(err.Error()) + x.v2.SetMessage(err.Error()) } // WrongMagicNumber describes failure status related to incorrect network magic. @@ -192,7 +192,7 @@ const defaultNodeUnderMaintenanceMsg = "node is under maintenance" // Error implements the error interface. func (x *NodeUnderMaintenance) Error() string { - msg := x.Message() + msg := x.v2.Message() if msg == "" { msg = defaultNodeUnderMaintenanceMsg } diff --git a/client/status/common_test.go b/client/status/common_test.go index 5a7a2b7..e55883e 100644 --- a/client/status/common_test.go +++ b/client/status/common_test.go @@ -3,7 +3,7 @@ package apistatus_test import ( "testing" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status" apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status" "github.com/stretchr/testify/require" ) diff --git a/client/status/container.go b/client/status/container.go index 9f06b27..594d984 100644 --- a/client/status/container.go +++ b/client/status/container.go @@ -1,8 +1,8 @@ package apistatus import ( - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status" ) // ContainerNotFound describes status of the failure because of the missing container. diff --git a/client/status/object.go b/client/status/object.go index 27ea86c..ae2e8e0 100644 --- a/client/status/object.go +++ b/client/status/object.go @@ -1,8 +1,8 @@ package apistatus import ( - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status" ) // ObjectLocked describes status of the failure because of the locked object. diff --git a/client/status/session.go b/client/status/session.go index 6f60758..f87ce61 100644 --- a/client/status/session.go +++ b/client/status/session.go @@ -1,8 +1,8 @@ package apistatus import ( - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status" ) // SessionTokenNotFound describes status of the failure because of the missing session token. diff --git a/client/status/success.go b/client/status/success.go index a68983d..3975b92 100644 --- a/client/status/success.go +++ b/client/status/success.go @@ -1,7 +1,7 @@ package apistatus import ( - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status" ) // SuccessDefaultV2 represents Status instance of default success. Implements StatusV2. diff --git a/client/status/unrecognized.go b/client/status/unrecognized.go index 19e481e..e4b4a81 100644 --- a/client/status/unrecognized.go +++ b/client/status/unrecognized.go @@ -1,7 +1,7 @@ package apistatus import ( - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status" ) type unrecognizedStatusV2 struct { diff --git a/client/status/v2.go b/client/status/v2.go index 5cee3be..95dfb8a 100644 --- a/client/status/v2.go +++ b/client/status/v2.go @@ -3,11 +3,11 @@ package apistatus import ( "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/apemanager" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/apemanager" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/object" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status" ) // StatusV2 defines a variety of Status instances compatible with FrostFS API V2 protocol. @@ -16,7 +16,7 @@ import ( type StatusV2 interface { Status - // ToStatusV2 returns the status as git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status.Status message structure. + // ToStatusV2 returns the status as git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/status.Status message structure. ToStatusV2() *status.Status } diff --git a/container/container.go b/container/container.go index 39c6259..ff63adb 100644 --- a/container/container.go +++ b/container/container.go @@ -9,9 +9,9 @@ import ( "strings" "time" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container" - v2netmap "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container" + v2netmap "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/netmap" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" @@ -37,7 +37,7 @@ import ( // Instances for existing containers can be initialized using decoding methods // (e.g Unmarshal). // -// Container is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container.Container +// Container is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container.Container // message. See ReadFromV2 / WriteToV2 methods. type Container struct { v2 container.Container diff --git a/container/container_test.go b/container/container_test.go index c5f1b7e..a66a866 100644 --- a/container/container_test.go +++ b/container/container_test.go @@ -6,9 +6,9 @@ import ( "testing" "time" - v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container" - v2netmap "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + v2container "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container" + v2netmap "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/netmap" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test" diff --git a/container/doc.go b/container/doc.go index 34b044d..85e2082 100644 --- a/container/doc.go +++ b/container/doc.go @@ -27,7 +27,7 @@ Instances can be also used to process FrostFS API V2 protocol messages On client side: - import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container" + import "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/container" var msg container.Container cnr.WriteToV2(&msg) diff --git a/container/id/id.go b/container/id/id.go index bde739c..569968a 100644 --- a/container/id/id.go +++ b/container/id/id.go @@ -4,13 +4,13 @@ import ( "crypto/sha256" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" "github.com/mr-tron/base58" ) // ID represents FrostFS container identifier. // -// ID is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs.ContainerID +// ID is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs.ContainerID // message. See ReadFromV2 / WriteToV2 methods. // // Instances can be created using built-in var declaration. diff --git a/container/id/id_test.go b/container/id/id_test.go index ded7457..6f60d92 100644 --- a/container/id/id_test.go +++ b/container/id/id_test.go @@ -5,7 +5,7 @@ import ( "crypto/sha256" "testing" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test" "github.com/mr-tron/base58" diff --git a/crypto/crypto_test.go b/crypto/crypto_test.go index 7d1ad52..da33d88 100644 --- a/crypto/crypto_test.go +++ b/crypto/crypto_test.go @@ -4,7 +4,7 @@ import ( "crypto/rand" "testing" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" diff --git a/crypto/doc.go b/crypto/doc.go index 8b568f5..7fc66c1 100644 --- a/crypto/doc.go +++ b/crypto/doc.go @@ -29,7 +29,7 @@ Signature can be also used to process FrostFS API V2 protocol messages On client side: - import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + import "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" var msg refs.Signature sig.WriteToV2(&msg) diff --git a/crypto/ecdsa/wallet_connect.go b/crypto/ecdsa/wallet_connect.go index 34cbcae..0fe8651 100644 --- a/crypto/ecdsa/wallet_connect.go +++ b/crypto/ecdsa/wallet_connect.go @@ -6,7 +6,7 @@ import ( "encoding/base64" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/util/signature/walletconnect" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/util/signature/walletconnect" frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" ) diff --git a/crypto/signature.go b/crypto/signature.go index 33c6132..f8a668e 100644 --- a/crypto/signature.go +++ b/crypto/signature.go @@ -4,13 +4,13 @@ import ( "errors" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" ) // Signature represents a confirmation of data integrity received by the // digital signature mechanism. // -// Signature is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs.Signature +// Signature is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs.Signature // message. See ReadFromV2 / WriteToV2 methods. // // Note that direct typecast is not safe and may result in loss of compatibility: diff --git a/crypto/signer.go b/crypto/signer.go index 9f99e3d..be96973 100644 --- a/crypto/signer.go +++ b/crypto/signer.go @@ -3,7 +3,7 @@ package frostfscrypto import ( "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" ) // Scheme represents digital signature algorithm with fixed cryptographic hash function. diff --git a/eacl/enums.go b/eacl/enums.go index b2b5353..8f693ec 100644 --- a/eacl/enums.go +++ b/eacl/enums.go @@ -1,7 +1,7 @@ package eacl import ( - v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" + v2acl "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" ) // Action taken if ContainerEACL record matched request. diff --git a/eacl/enums_test.go b/eacl/enums_test.go index 29f2518..e283b09 100644 --- a/eacl/enums_test.go +++ b/eacl/enums_test.go @@ -3,7 +3,7 @@ package eacl_test import ( "testing" - v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" + v2acl "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl" "github.com/stretchr/testify/require" ) diff --git a/eacl/filter.go b/eacl/filter.go index 4403e5a..af32eae 100644 --- a/eacl/filter.go +++ b/eacl/filter.go @@ -3,7 +3,7 @@ package eacl import ( "strconv" - v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" + v2acl "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" ) // Filter defines check conditions if request header is matched or not. Matched diff --git a/eacl/filter_test.go b/eacl/filter_test.go index 74b9a10..3a01a32 100644 --- a/eacl/filter_test.go +++ b/eacl/filter_test.go @@ -4,7 +4,7 @@ import ( "strconv" "testing" - v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" + v2acl "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" "github.com/stretchr/testify/require" ) diff --git a/eacl/record.go b/eacl/record.go index 3c0d44a..c808387 100644 --- a/eacl/record.go +++ b/eacl/record.go @@ -3,7 +3,7 @@ package eacl import ( "crypto/ecdsa" - v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" + v2acl "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" diff --git a/eacl/record_test.go b/eacl/record_test.go index a1738fc..02301da 100644 --- a/eacl/record_test.go +++ b/eacl/record_test.go @@ -5,7 +5,7 @@ import ( "fmt" "testing" - v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" + v2acl "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" checksumtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum/test" cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object" diff --git a/eacl/table.go b/eacl/table.go index 6982b85..3fc9e60 100644 --- a/eacl/table.go +++ b/eacl/table.go @@ -4,8 +4,8 @@ import ( "crypto/sha256" "fmt" - v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + v2acl "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version" ) diff --git a/eacl/table_test.go b/eacl/table_test.go index 4ec110f..630d3ed 100644 --- a/eacl/table_test.go +++ b/eacl/table_test.go @@ -4,7 +4,7 @@ import ( "crypto/sha256" "testing" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl" eacltest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl/test" diff --git a/eacl/target.go b/eacl/target.go index 2b8b709..a2f9c36 100644 --- a/eacl/target.go +++ b/eacl/target.go @@ -4,7 +4,7 @@ import ( "bytes" "crypto/ecdsa" - v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" + v2acl "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" ) diff --git a/eacl/target_test.go b/eacl/target_test.go index e226194..9da4f82 100644 --- a/eacl/target_test.go +++ b/eacl/target_test.go @@ -4,7 +4,7 @@ import ( "crypto/ecdsa" "testing" - v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl" + v2acl "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/acl" "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/stretchr/testify/require" ) diff --git a/go.mod b/go.mod index 7c46916..ed14604 100644 --- a/go.mod +++ b/go.mod @@ -3,34 +3,35 @@ module git.frostfs.info/TrueCloudLab/frostfs-sdk-go go 1.22 require ( - git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20241011114054-f0fc40e116d1 git.frostfs.info/TrueCloudLab/frostfs-contract v0.19.3-0.20240621131249-49e5270f673e + git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 git.frostfs.info/TrueCloudLab/hrw v1.2.1 git.frostfs.info/TrueCloudLab/tzhash v1.8.0 + github.com/VictoriaMetrics/easyproto v0.1.4 github.com/antlr4-go/antlr/v4 v4.13.1 github.com/google/uuid v1.6.0 github.com/hashicorp/golang-lru/v2 v2.0.7 github.com/klauspost/reedsolomon v1.12.1 + github.com/mailru/easyjson v0.7.7 github.com/mr-tron/base58 v1.2.0 github.com/nspcc-dev/neo-go v0.106.2 github.com/stretchr/testify v1.9.0 go.uber.org/zap v1.27.0 + golang.org/x/sync v0.7.0 google.golang.org/grpc v1.66.2 google.golang.org/protobuf v1.34.1 gopkg.in/yaml.v3 v3.0.1 ) require ( - git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 // indirect git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0 // indirect - github.com/VictoriaMetrics/easyproto v0.1.4 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect github.com/golang/snappy v0.0.1 // indirect github.com/gorilla/websocket v1.5.1 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/klauspost/cpuid/v2 v2.2.6 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/kr/pretty v0.1.0 // indirect github.com/nspcc-dev/go-ordered-json v0.0.0-20240301084351-0246b013f8b2 // indirect github.com/nspcc-dev/neo-go/pkg/interop v0.0.0-20240521091047-78685785716d // indirect github.com/nspcc-dev/rfc6979 v0.2.1 // indirect @@ -42,8 +43,8 @@ require ( golang.org/x/crypto v0.24.0 // indirect golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect golang.org/x/net v0.26.0 // indirect - golang.org/x/sync v0.7.0 // indirect golang.org/x/sys v0.21.0 // indirect golang.org/x/text v0.16.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240604185151-ef581f913117 // indirect + gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect ) diff --git a/go.sum b/go.sum index 7451104de1e04f620c4e33bc30535bdd724ba44b..56930c779a92b45099c8646bf7fe31a3ba0ab9b9 100644 GIT binary patch delta 153 zcmey|&Dhw@I6-alK1RLG>5MVr4h1EZ3T1|RK&YRdua}#jqL5)|Rp1sFnP+Ae?os4l z5D@8?lU45TTbOTX5Rx64VVG8FoE({%Z}7Jzu}fNTJL~&(KWIP}e}u$iT?N(7+G~Obkp-bkhvdl1&U! z4Gqmw3>7jAtuo7!Qz`;e16}eeOp1%#j8d!e6H~)-+zi|tE0cpAt4hk#JVU+mLOo52 zC-XCEq>^ZbetN!MZhi{LCO1>}VDpTiBr~Ic&`Q(dkVqG2lf|~<_Xt16ALnR)ARMqj5av0P$88E0Zarfzz^ewoq6h85fZPU#1S diff --git a/prepare.sh b/prepare.sh new file mode 100755 index 0000000..a7b6100 --- /dev/null +++ b/prepare.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +if [ -z "$1" ]; then + echo "usage: ./prepare.sh path/to/frostfs-api" + exit 1 +fi + +API_GO_PATH=$(pwd)/api +API_PATH=$1 + +# MOVE FILES FROM API REPO +cd "$API_PATH" || exit 1 +ARGS=$(find ./ -name '*.proto' -not -path './bin/*') +for file in $ARGS; do + dir=$(dirname "$file") + mkdir -p "$API_GO_PATH/$dir/grpc" + cp -r "$dir"/* "$API_GO_PATH/$dir/grpc" +done + +# MODIFY FILES +cd "$API_GO_PATH" || exit 1 +ARGS2=$(find ./ -name '*.proto' -not -path './bin/*') +for file in $ARGS2; do + echo "$file" + sed -i "s/import\ \"\(.*\)\/\(.*\)\.proto\";/import\ \"\1\/grpc\/\2\.proto\";/" $file + sed -i "s/api-go\\/v2/sdk-go\\/api/" $file + sed -i "s/import \"/import \"api\//" $file +done + + +cd "$API_GO_PATH/.." || exit 1 +# COMPILE +make protoc + +# REMOVE PROTO DEFINITIONS +ARGS=$(find ./$prefix -name '*.proto' -not -path './util/*' -not -path './bin/*') +for file in $ARGS; do + rm "$file" +done diff --git a/session/common.go b/session/common.go index b103b59..3d7308f 100644 --- a/session/common.go +++ b/session/common.go @@ -6,8 +6,8 @@ import ( "errors" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" diff --git a/session/container.go b/session/container.go index 45c5ff8..463523b 100644 --- a/session/container.go +++ b/session/container.go @@ -5,8 +5,8 @@ import ( "errors" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" @@ -18,7 +18,7 @@ import ( // limited validity period, and applies to a strictly defined set of operations. // See methods for details. // -// Container is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session.Token +// Container is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session.Token // message. See ReadFromV2 / WriteToV2 methods. // // Instances can be created using built-in var declaration. diff --git a/session/container_test.go b/session/container_test.go index 73fd815..fcf152d 100644 --- a/session/container_test.go +++ b/session/container_test.go @@ -8,8 +8,8 @@ import ( mrand "math/rand" "testing" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + v2session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test" frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa" diff --git a/session/doc.go b/session/doc.go index 12ec0c4..98858f7 100644 --- a/session/doc.go +++ b/session/doc.go @@ -28,7 +28,7 @@ Instances can be also used to process FrostFS API V2 protocol messages On client side: - import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" + import "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" var msg session.Token tok.WriteToV2(&msg) diff --git a/session/object.go b/session/object.go index 3641bd1..385ca03 100644 --- a/session/object.go +++ b/session/object.go @@ -5,8 +5,8 @@ import ( "errors" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id" oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id" ) @@ -17,7 +17,7 @@ import ( // limited validity period, and applies to a strictly defined set of operations. // See methods for details. // -// Object is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session.Token +// Object is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session.Token // message. See ReadFromV2 / WriteToV2 methods. // // Instances can be created using built-in var declaration. diff --git a/session/object_test.go b/session/object_test.go index 59ff8d6..4d20773 100644 --- a/session/object_test.go +++ b/session/object_test.go @@ -8,8 +8,8 @@ import ( "math/rand" "testing" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" - v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" + v2session "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/session" cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test" frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa" diff --git a/user/doc.go b/user/doc.go index 4809e4a..d4e0b4b 100644 --- a/user/doc.go +++ b/user/doc.go @@ -39,7 +39,7 @@ Instances can be also used to process FrostFS API protocol messages On client side: - import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + import "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" var msg refs.OwnerID id.WriteToV2(&msg) diff --git a/user/id.go b/user/id.go index 31ff9b6..2d64d43 100644 --- a/user/id.go +++ b/user/id.go @@ -5,7 +5,7 @@ import ( "errors" "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" "github.com/mr-tron/base58" "github.com/nspcc-dev/neo-go/pkg/crypto/hash" "github.com/nspcc-dev/neo-go/pkg/encoding/address" @@ -18,7 +18,7 @@ var zeroSlice = bytes.Repeat([]byte{0}, idSize) // ID identifies users of the FrostFS system. // -// ID is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs.OwnerID +// ID is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs.OwnerID // message. See ReadFromV2 / WriteToV2 methods. // // Instances can be created using built-in var declaration. Zero ID is not valid, diff --git a/user/id_test.go b/user/id_test.go index 9867472..afeb746 100644 --- a/user/id_test.go +++ b/user/id_test.go @@ -5,7 +5,7 @@ import ( "crypto/rand" "testing" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" . "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user" usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test" "github.com/mr-tron/base58" diff --git a/version/version.go b/version/version.go index 47e61c8..2411966 100644 --- a/version/version.go +++ b/version/version.go @@ -3,12 +3,12 @@ package version import ( "fmt" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" ) // Version represents revision number in SemVer scheme. // -// Version is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs.Version +// Version is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs.Version // message. See ReadFromV2 / WriteToV2 methods. // // Instances can be created using built-in var declaration. diff --git a/version/version_test.go b/version/version_test.go index fdf2b6a..97cec9a 100644 --- a/version/version_test.go +++ b/version/version_test.go @@ -3,7 +3,7 @@ package version import ( "testing" - "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" + "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/api/refs" "github.com/stretchr/testify/require" )