From 6e01a0ead7b419a0d357f097b5f76da1cb37cd56 Mon Sep 17 00:00:00 2001 From: Denis Kirillov Date: Thu, 28 Jul 2022 19:57:40 +0300 Subject: [PATCH] [#33] Add route to get NeoFS balance Signed-off-by: Denis Kirillov --- gen/models/balance.go | 105 +++++++++++++++++ gen/restapi/embedded_spec.go | 106 ++++++++++++++++++ gen/restapi/operations/get_balance.go | 58 ++++++++++ .../operations/get_balance_parameters.go | 71 ++++++++++++ .../operations/get_balance_responses.go | 102 +++++++++++++++++ gen/restapi/operations/neofs_rest_gw_api.go | 12 ++ handlers/api.go | 2 + handlers/balance.go | 37 ++++++ spec/rest.yaml | 37 ++++++ 9 files changed, 530 insertions(+) create mode 100644 gen/models/balance.go create mode 100644 gen/restapi/operations/get_balance.go create mode 100644 gen/restapi/operations/get_balance_parameters.go create mode 100644 gen/restapi/operations/get_balance_responses.go create mode 100644 handlers/balance.go diff --git a/gen/models/balance.go b/gen/models/balance.go new file mode 100644 index 0000000..325cce5 --- /dev/null +++ b/gen/models/balance.go @@ -0,0 +1,105 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package models + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "context" + + "github.com/go-openapi/errors" + "github.com/go-openapi/strfmt" + "github.com/go-openapi/swag" + "github.com/go-openapi/validate" +) + +// Balance balance +// +// swagger:model Balance +type Balance struct { + + // address + // Required: true + Address *string `json:"address"` + + // precision + // Required: true + Precision *int64 `json:"precision"` + + // value + // Required: true + Value *string `json:"value"` +} + +// Validate validates this balance +func (m *Balance) Validate(formats strfmt.Registry) error { + var res []error + + if err := m.validateAddress(formats); err != nil { + res = append(res, err) + } + + if err := m.validatePrecision(formats); err != nil { + res = append(res, err) + } + + if err := m.validateValue(formats); err != nil { + res = append(res, err) + } + + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +func (m *Balance) validateAddress(formats strfmt.Registry) error { + + if err := validate.Required("address", "body", m.Address); err != nil { + return err + } + + return nil +} + +func (m *Balance) validatePrecision(formats strfmt.Registry) error { + + if err := validate.Required("precision", "body", m.Precision); err != nil { + return err + } + + return nil +} + +func (m *Balance) validateValue(formats strfmt.Registry) error { + + if err := validate.Required("value", "body", m.Value); err != nil { + return err + } + + return nil +} + +// ContextValidate validates this balance based on context it is used +func (m *Balance) ContextValidate(ctx context.Context, formats strfmt.Registry) error { + return nil +} + +// MarshalBinary interface implementation +func (m *Balance) MarshalBinary() ([]byte, error) { + if m == nil { + return nil, nil + } + return swag.WriteJSON(m) +} + +// UnmarshalBinary interface implementation +func (m *Balance) UnmarshalBinary(b []byte) error { + var res Balance + if err := swag.ReadJSON(b, &res); err != nil { + return err + } + *m = res + return nil +} diff --git a/gen/restapi/embedded_spec.go b/gen/restapi/embedded_spec.go index 4cfe306..db20100 100644 --- a/gen/restapi/embedded_spec.go +++ b/gen/restapi/embedded_spec.go @@ -30,6 +30,40 @@ func init() { "host": "localhost:8090", "basePath": "/v1", "paths": { + "/accounting/balance/{address}": { + "get": { + "security": [], + "description": "Getting balance of provided wallet address in NeoFS.", + "produces": [ + "application/json" + ], + "summary": "Get balance in NeoFS", + "operationId": "getBalance", + "parameters": [ + { + "type": "string", + "description": "Base58 encoded wallet address.", + "name": "address", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Balance of address in NeoFS", + "schema": { + "$ref": "#/definitions/Balance" + } + }, + "400": { + "description": "Bad request", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, "/auth": { "post": { "security": [], @@ -546,6 +580,25 @@ func init() { "value": "tag value" } }, + "Balance": { + "type": "object", + "required": [ + "address", + "value", + "precision" + ], + "properties": { + "address": { + "type": "string" + }, + "precision": { + "type": "integer" + }, + "value": { + "type": "string" + } + } + }, "Bearer": { "description": "Bearer token that is expected to be formed.", "type": "object", @@ -1305,6 +1358,40 @@ func init() { "host": "localhost:8090", "basePath": "/v1", "paths": { + "/accounting/balance/{address}": { + "get": { + "security": [], + "description": "Getting balance of provided wallet address in NeoFS.", + "produces": [ + "application/json" + ], + "summary": "Get balance in NeoFS", + "operationId": "getBalance", + "parameters": [ + { + "type": "string", + "description": "Base58 encoded wallet address.", + "name": "address", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "Balance of address in NeoFS", + "schema": { + "$ref": "#/definitions/Balance" + } + }, + "400": { + "description": "Bad request", + "schema": { + "$ref": "#/definitions/ErrorResponse" + } + } + } + } + }, "/auth": { "post": { "security": [], @@ -1917,6 +2004,25 @@ func init() { "value": "tag value" } }, + "Balance": { + "type": "object", + "required": [ + "address", + "value", + "precision" + ], + "properties": { + "address": { + "type": "string" + }, + "precision": { + "type": "integer" + }, + "value": { + "type": "string" + } + } + }, "Bearer": { "description": "Bearer token that is expected to be formed.", "type": "object", diff --git a/gen/restapi/operations/get_balance.go b/gen/restapi/operations/get_balance.go new file mode 100644 index 0000000..70fe0db --- /dev/null +++ b/gen/restapi/operations/get_balance.go @@ -0,0 +1,58 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package operations + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime/middleware" +) + +// GetBalanceHandlerFunc turns a function with the right signature into a get balance handler +type GetBalanceHandlerFunc func(GetBalanceParams) middleware.Responder + +// Handle executing the request and returning a response +func (fn GetBalanceHandlerFunc) Handle(params GetBalanceParams) middleware.Responder { + return fn(params) +} + +// GetBalanceHandler interface for that can handle valid get balance params +type GetBalanceHandler interface { + Handle(GetBalanceParams) middleware.Responder +} + +// NewGetBalance creates a new http.Handler for the get balance operation +func NewGetBalance(ctx *middleware.Context, handler GetBalanceHandler) *GetBalance { + return &GetBalance{Context: ctx, Handler: handler} +} + +/* GetBalance swagger:route GET /accounting/balance/{address} getBalance + +Get balance in NeoFS + +Getting balance of provided wallet address in NeoFS. + +*/ +type GetBalance struct { + Context *middleware.Context + Handler GetBalanceHandler +} + +func (o *GetBalance) ServeHTTP(rw http.ResponseWriter, r *http.Request) { + route, rCtx, _ := o.Context.RouteInfo(r) + if rCtx != nil { + *r = *rCtx + } + var Params = NewGetBalanceParams() + if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params + o.Context.Respond(rw, r, route.Produces, route, err) + return + } + + res := o.Handler.Handle(Params) // actually handle the request + o.Context.Respond(rw, r, route.Produces, route, res) + +} diff --git a/gen/restapi/operations/get_balance_parameters.go b/gen/restapi/operations/get_balance_parameters.go new file mode 100644 index 0000000..0eb3890 --- /dev/null +++ b/gen/restapi/operations/get_balance_parameters.go @@ -0,0 +1,71 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package operations + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/errors" + "github.com/go-openapi/runtime/middleware" + "github.com/go-openapi/strfmt" +) + +// NewGetBalanceParams creates a new GetBalanceParams object +// +// There are no default values defined in the spec. +func NewGetBalanceParams() GetBalanceParams { + + return GetBalanceParams{} +} + +// GetBalanceParams contains all the bound params for the get balance operation +// typically these are obtained from a http.Request +// +// swagger:parameters getBalance +type GetBalanceParams struct { + + // HTTP Request Object + HTTPRequest *http.Request `json:"-"` + + /*Base58 encoded wallet address. + Required: true + In: path + */ + Address string +} + +// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface +// for simple values it will use straight method calls. +// +// To ensure default values, the struct must have been initialized with NewGetBalanceParams() beforehand. +func (o *GetBalanceParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error { + var res []error + + o.HTTPRequest = r + + rAddress, rhkAddress, _ := route.Params.GetOK("address") + if err := o.bindAddress(rAddress, rhkAddress, route.Formats); err != nil { + res = append(res, err) + } + if len(res) > 0 { + return errors.CompositeValidationError(res...) + } + return nil +} + +// bindAddress binds and validates parameter Address from path. +func (o *GetBalanceParams) bindAddress(rawData []string, hasKey bool, formats strfmt.Registry) error { + var raw string + if len(rawData) > 0 { + raw = rawData[len(rawData)-1] + } + + // Required: true + // Parameter is provided by construction from the route + o.Address = raw + + return nil +} diff --git a/gen/restapi/operations/get_balance_responses.go b/gen/restapi/operations/get_balance_responses.go new file mode 100644 index 0000000..09b7e41 --- /dev/null +++ b/gen/restapi/operations/get_balance_responses.go @@ -0,0 +1,102 @@ +// Code generated by go-swagger; DO NOT EDIT. + +package operations + +// This file was generated by the swagger tool. +// Editing this file might prove futile when you re-run the swagger generate command + +import ( + "net/http" + + "github.com/go-openapi/runtime" + + "github.com/nspcc-dev/neofs-rest-gw/gen/models" +) + +// GetBalanceOKCode is the HTTP code returned for type GetBalanceOK +const GetBalanceOKCode int = 200 + +/*GetBalanceOK Balance of address in NeoFS + +swagger:response getBalanceOK +*/ +type GetBalanceOK struct { + + /* + In: Body + */ + Payload *models.Balance `json:"body,omitempty"` +} + +// NewGetBalanceOK creates GetBalanceOK with default headers values +func NewGetBalanceOK() *GetBalanceOK { + + return &GetBalanceOK{} +} + +// WithPayload adds the payload to the get balance o k response +func (o *GetBalanceOK) WithPayload(payload *models.Balance) *GetBalanceOK { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get balance o k response +func (o *GetBalanceOK) SetPayload(payload *models.Balance) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetBalanceOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(200) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} + +// GetBalanceBadRequestCode is the HTTP code returned for type GetBalanceBadRequest +const GetBalanceBadRequestCode int = 400 + +/*GetBalanceBadRequest Bad request + +swagger:response getBalanceBadRequest +*/ +type GetBalanceBadRequest struct { + + /* + In: Body + */ + Payload *models.ErrorResponse `json:"body,omitempty"` +} + +// NewGetBalanceBadRequest creates GetBalanceBadRequest with default headers values +func NewGetBalanceBadRequest() *GetBalanceBadRequest { + + return &GetBalanceBadRequest{} +} + +// WithPayload adds the payload to the get balance bad request response +func (o *GetBalanceBadRequest) WithPayload(payload *models.ErrorResponse) *GetBalanceBadRequest { + o.Payload = payload + return o +} + +// SetPayload sets the payload to the get balance bad request response +func (o *GetBalanceBadRequest) SetPayload(payload *models.ErrorResponse) { + o.Payload = payload +} + +// WriteResponse to the client +func (o *GetBalanceBadRequest) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) { + + rw.WriteHeader(400) + if o.Payload != nil { + payload := o.Payload + if err := producer.Produce(rw, payload); err != nil { + panic(err) // let the recovery middleware deal with this + } + } +} diff --git a/gen/restapi/operations/neofs_rest_gw_api.go b/gen/restapi/operations/neofs_rest_gw_api.go index 57684e1..e0203c5 100644 --- a/gen/restapi/operations/neofs_rest_gw_api.go +++ b/gen/restapi/operations/neofs_rest_gw_api.go @@ -53,6 +53,9 @@ func NewNeofsRestGwAPI(spec *loads.Document) *NeofsRestGwAPI { DeleteObjectHandler: DeleteObjectHandlerFunc(func(params DeleteObjectParams, principal *models.Principal) middleware.Responder { return middleware.NotImplemented("operation DeleteObject has not yet been implemented") }), + GetBalanceHandler: GetBalanceHandlerFunc(func(params GetBalanceParams) middleware.Responder { + return middleware.NotImplemented("operation GetBalance has not yet been implemented") + }), GetContainerHandler: GetContainerHandlerFunc(func(params GetContainerParams) middleware.Responder { return middleware.NotImplemented("operation GetContainer has not yet been implemented") }), @@ -133,6 +136,8 @@ type NeofsRestGwAPI struct { DeleteContainerHandler DeleteContainerHandler // DeleteObjectHandler sets the operation handler for the delete object operation DeleteObjectHandler DeleteObjectHandler + // GetBalanceHandler sets the operation handler for the get balance operation + GetBalanceHandler GetBalanceHandler // GetContainerHandler sets the operation handler for the get container operation GetContainerHandler GetContainerHandler // GetContainerEACLHandler sets the operation handler for the get container e ACL operation @@ -239,6 +244,9 @@ func (o *NeofsRestGwAPI) Validate() error { if o.DeleteObjectHandler == nil { unregistered = append(unregistered, "DeleteObjectHandler") } + if o.GetBalanceHandler == nil { + unregistered = append(unregistered, "GetBalanceHandler") + } if o.GetContainerHandler == nil { unregistered = append(unregistered, "GetContainerHandler") } @@ -377,6 +385,10 @@ func (o *NeofsRestGwAPI) initHandlerCache() { if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) } + o.handlers["GET"]["/accounting/balance/{address}"] = NewGetBalance(o.context, o.GetBalanceHandler) + if o.handlers["GET"] == nil { + o.handlers["GET"] = make(map[string]http.Handler) + } o.handlers["GET"]["/containers/{containerId}"] = NewGetContainer(o.context, o.GetContainerHandler) if o.handlers["GET"] == nil { o.handlers["GET"] = make(map[string]http.Handler) diff --git a/handlers/api.go b/handlers/api.go index f40879c..21eaee7 100644 --- a/handlers/api.go +++ b/handlers/api.go @@ -80,6 +80,8 @@ func (a *API) Configure(api *operations.NeofsRestGwAPI) http.Handler { api.AuthHandler = operations.AuthHandlerFunc(a.PostAuth) + api.GetBalanceHandler = operations.GetBalanceHandlerFunc(a.Balance) + api.PutObjectHandler = operations.PutObjectHandlerFunc(a.PutObjects) api.GetObjectInfoHandler = operations.GetObjectInfoHandlerFunc(a.GetObjectInfo) api.DeleteObjectHandler = operations.DeleteObjectHandlerFunc(a.DeleteObject) diff --git a/handlers/balance.go b/handlers/balance.go new file mode 100644 index 0000000..0122b8c --- /dev/null +++ b/handlers/balance.go @@ -0,0 +1,37 @@ +package handlers + +import ( + "strconv" + + "github.com/go-openapi/runtime/middleware" + "github.com/nspcc-dev/neofs-rest-gw/gen/models" + "github.com/nspcc-dev/neofs-rest-gw/gen/restapi/operations" + "github.com/nspcc-dev/neofs-rest-gw/internal/util" + "github.com/nspcc-dev/neofs-sdk-go/pool" + "github.com/nspcc-dev/neofs-sdk-go/user" +) + +// Balance handler that get balance from NeoFS. +func (a *API) Balance(params operations.GetBalanceParams) middleware.Responder { + var ownerID user.ID + if err := ownerID.DecodeString(params.Address); err != nil { + resp := a.logAndGetErrorResponse("parse address", err) + return operations.NewGetBalanceBadRequest().WithPayload(resp) + } + + var prm pool.PrmBalanceGet + prm.SetAccount(ownerID) + + neofsBalance, err := a.pool.Balance(params.HTTPRequest.Context(), prm) + if err != nil { + resp := a.logAndGetErrorResponse("get balance", err) + return operations.NewGetBalanceBadRequest().WithPayload(resp) + } + + var resp models.Balance + resp.Address = util.NewString(params.Address) + resp.Value = util.NewString(strconv.FormatInt(neofsBalance.Value(), 10)) + resp.Precision = util.NewInteger(int64(neofsBalance.Precision())) + + return operations.NewGetBalanceOK().WithPayload(&resp) +} diff --git a/spec/rest.yaml b/spec/rest.yaml index b72fb47..f8aeb3d 100644 --- a/spec/rest.yaml +++ b/spec/rest.yaml @@ -92,6 +92,30 @@ paths: schema: $ref: '#/definitions/ErrorResponse' + /accounting/balance/{address}: + get: + operationId: getBalance + summary: Get balance in NeoFS + description: Getting balance of provided wallet address in NeoFS. + security: [ ] + parameters: + - in: path + name: address + type: string + required: true + description: Base58 encoded wallet address. + produces: + - application/json + responses: + 200: + description: Balance of address in NeoFS + schema: + $ref: '#/definitions/Balance' + 400: + description: Bad request + schema: + $ref: '#/definitions/ErrorResponse' + /objects: parameters: - $ref: '#/parameters/signatureParam' @@ -822,6 +846,19 @@ definitions: value: "tag value" Principal: type: string + Balance: + type: object + properties: + address: + type: string + value: + type: string + precision: + type: integer + required: + - address + - value + - precision ErrorType: description: Error type. Allow determine source of the error. type: string