Skip to content

Commit

Permalink
Merge pull request #251 from nspcc-dev/247-rest-gw-doesnt-take-into-a…
Browse files Browse the repository at this point in the history
…ccount-updated-network-settings

Cache network settings
  • Loading branch information
roman-khimov authored Oct 23, 2024
2 parents 23424c7 + 309119b commit e1b12eb
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 22 deletions.
9 changes: 9 additions & 0 deletions handlers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import (
"github.com/labstack/echo/v4"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neofs-rest-gw/handlers/apiserver"
"github.com/nspcc-dev/neofs-rest-gw/internal/cache"
"github.com/nspcc-dev/neofs-rest-gw/internal/util"
"github.com/nspcc-dev/neofs-rest-gw/metrics"
"github.com/nspcc-dev/neofs-sdk-go/netmap"
"github.com/nspcc-dev/neofs-sdk-go/pool"
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/nspcc-dev/neofs-sdk-go/user"
Expand Down Expand Up @@ -45,6 +47,11 @@ type SessionToken struct {
Verb session.ContainerVerb
}

type networkInfoGetter interface {
NetworkInfo(ctx context.Context) (netmap.NetworkInfo, error)
StoreNetworkInfo(ni netmap.NetworkInfo)
}

const (
// bearerCookieName is the name of the bearer cookie.
bearerCookieName = "Bearer"
Expand Down Expand Up @@ -75,6 +82,7 @@ func NewAPI(prm *PrmAPI) (*RestAPI, error) {
pprofService: prm.PprofService,
gateMetric: prm.GateMetric,
serviceShutdownTimeout: prm.ServiceShutdownTimeout,
networkInfoGetter: cache.NewNetworkInfoCache(prm.Pool),
}, nil
}

Expand Down Expand Up @@ -141,6 +149,7 @@ type RestAPI struct {
prometheusService *metrics.Service
pprofService *metrics.Service
serviceShutdownTimeout time.Duration
networkInfoGetter networkInfoGetter
}

func (a *RestAPI) StartCallback() {
Expand Down
22 changes: 10 additions & 12 deletions handlers/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,7 @@ import (
"github.com/labstack/echo/v4"
"github.com/nspcc-dev/neofs-rest-gw/handlers/apiserver"
"github.com/nspcc-dev/neofs-rest-gw/internal/util"
"github.com/nspcc-dev/neofs-sdk-go/client"
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
"github.com/nspcc-dev/neofs-sdk-go/pool"
"github.com/nspcc-dev/neofs-sdk-go/user"
)

Expand Down Expand Up @@ -91,10 +89,10 @@ func (a *RestAPI) Auth(ctx echo.Context, params apiserver.AuthParams) error {

if isObject {
prm := newObjectParams(commonPrm, token)
response[i], err = prepareObjectToken(ctx.Request().Context(), prm, a.pool, a.signer.UserID())
response[i], err = prepareObjectToken(ctx.Request().Context(), prm, a.networkInfoGetter, a.signer.UserID())
} else {
prm := newContainerParams(commonPrm, token)
response[i], err = prepareContainerTokens(ctx.Request().Context(), prm, a.pool, a.signer.Public())
response[i], err = prepareContainerTokens(ctx.Request().Context(), prm, a.networkInfoGetter, a.signer.Public())
}

if err != nil {
Expand Down Expand Up @@ -136,7 +134,7 @@ func (a *RestAPI) FormBinaryBearer(ctx echo.Context, params apiserver.FormBinary
return ctx.JSON(http.StatusOK, resp)
}

func prepareObjectToken(ctx context.Context, params objectTokenParams, pool *pool.Pool, owner user.ID) (*apiserver.TokenResponse, error) {
func prepareObjectToken(ctx context.Context, params objectTokenParams, networkInfoGetter networkInfoGetter, owner user.ID) (*apiserver.TokenResponse, error) {
btoken, err := util.ToNativeObjectToken(params.Records)
if err != nil {
return nil, fmt.Errorf("couldn't transform token to native: %w", err)
Expand All @@ -152,7 +150,7 @@ func prepareObjectToken(ctx context.Context, params objectTokenParams, pool *poo
btoken.ForUser(owner)
}

iat, exp, err := getTokenLifetime(ctx, pool, params.XBearerLifetime)
iat, exp, err := getTokenLifetime(ctx, networkInfoGetter, params.XBearerLifetime)
if err != nil {
return nil, fmt.Errorf("couldn't get lifetime: %w", err)
}
Expand All @@ -168,8 +166,8 @@ func prepareObjectToken(ctx context.Context, params objectTokenParams, pool *poo
}, nil
}

func prepareContainerTokens(ctx context.Context, params containerTokenParams, pool *pool.Pool, pubKey neofscrypto.PublicKey) (*apiserver.TokenResponse, error) {
iat, exp, err := getTokenLifetime(ctx, pool, params.XBearerLifetime)
func prepareContainerTokens(ctx context.Context, params containerTokenParams, networkInfoGetter networkInfoGetter, pubKey neofscrypto.PublicKey) (*apiserver.TokenResponse, error) {
iat, exp, err := getTokenLifetime(ctx, networkInfoGetter, params.XBearerLifetime)
if err != nil {
return nil, fmt.Errorf("couldn't get lifetime: %w", err)
}
Expand Down Expand Up @@ -204,17 +202,17 @@ func prepareContainerTokens(ctx context.Context, params containerTokenParams, po
}, nil
}

func getCurrentEpoch(ctx context.Context, p *pool.Pool) (uint64, error) {
netInfo, err := p.NetworkInfo(ctx, client.PrmNetworkInfo{})
func getCurrentEpoch(ctx context.Context, networkInfoGetter networkInfoGetter) (uint64, error) {
netInfo, err := networkInfoGetter.NetworkInfo(ctx)
if err != nil {
return 0, fmt.Errorf("couldn't get netwokr info: %w", err)
}

return netInfo.CurrentEpoch(), nil
}

func getTokenLifetime(ctx context.Context, p *pool.Pool, expDuration uint64) (uint64, uint64, error) {
currEpoch, err := getCurrentEpoch(ctx, p)
func getTokenLifetime(ctx context.Context, networkInfoGetter networkInfoGetter, expDuration uint64) (uint64, uint64, error) {
currEpoch, err := getCurrentEpoch(ctx, networkInfoGetter)
if err != nil {
return 0, 0, err
}
Expand Down
13 changes: 11 additions & 2 deletions handlers/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func (a *RestAPI) PutContainer(ctx echo.Context, params apiserver.PutContainerPa
return ctx.JSON(http.StatusBadRequest, resp)
}

cnrID, err := createContainer(ctx.Request().Context(), a.pool, stoken, body, params, a.signer)
cnrID, err := createContainer(ctx.Request().Context(), a.pool, stoken, body, params, a.signer, a.networkInfoGetter)
if err != nil {
resp := a.logAndGetErrorResponse("create container", err)
return ctx.JSON(http.StatusBadRequest, resp)
Expand Down Expand Up @@ -381,7 +381,7 @@ func getContainerEACL(ctx context.Context, p *pool.Pool, cnrID cid.ID) (*apiserv
return tableResp, nil
}

func createContainer(ctx context.Context, p *pool.Pool, stoken session.Container, request apiserver.ContainerPutInfo, params apiserver.PutContainerParams, signer user.Signer) (cid.ID, error) {
func createContainer(ctx context.Context, p *pool.Pool, stoken session.Container, request apiserver.ContainerPutInfo, params apiserver.PutContainerParams, signer user.Signer, networkInfoGetter networkInfoGetter) (cid.ID, error) {
if request.PlacementPolicy == "" {
request.PlacementPolicy = defaultPlacementPolicy
}
Expand All @@ -406,6 +406,15 @@ func createContainer(ctx context.Context, p *pool.Pool, stoken session.Container
cnr.SetBasicACL(basicACL)
cnr.SetOwner(stoken.Issuer())

ni, err := networkInfoGetter.NetworkInfo(ctx)
if err != nil {
return cid.ID{}, fmt.Errorf("couldn't get network info: %w", err)
}

if ni.HomomorphicHashingDisabled() {
cnr.DisableHomomorphicHashing()
}

cnr.SetCreationTime(time.Now())

if request.ContainerName != "" {
Expand Down
2 changes: 2 additions & 0 deletions handlers/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ func (a *RestAPI) GetNetworkInfo(ctx echo.Context) error {
return ctx.JSON(http.StatusBadRequest, resp)
}

a.networkInfoGetter.StoreNetworkInfo(networkInfo)

var resp apiserver.NetworkInfoOK
resp.AuditFee = networkInfo.AuditFee()
resp.StoragePrice = networkInfo.StoragePrice()
Expand Down
2 changes: 1 addition & 1 deletion handlers/newObjects.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func (a *RestAPI) NewUploadContainerObject(ctx echo.Context, containerID apiserv

addExpirationHeaders(filtered, params)
if needParseExpiration(filtered) {
epochDuration, err := getEpochDurations(ctx.Request().Context(), a.pool)
epochDuration, err := getEpochDurations(ctx.Request().Context(), a.networkInfoGetter)
if err != nil {
resp := a.logAndGetErrorResponse("could not get epoch durations from network info", err)
return ctx.JSON(http.StatusBadRequest, resp)
Expand Down
4 changes: 2 additions & 2 deletions handlers/objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ func (a *RestAPI) PutObject(ctx echo.Context, params apiserver.PutObjectParams)
DefaultTimestamp: a.defaultTimestamp,
DefaultFileName: body.FileName,
}
attributes, err := getObjectAttributes(ctx.Request().Context(), a.pool, body.Attributes, prm)
attributes, err := getObjectAttributes(ctx.Request().Context(), a.networkInfoGetter, body.Attributes, prm)
if err != nil {
resp := a.logAndGetErrorResponse("failed to get object attributes", err)
return ctx.JSON(http.StatusBadRequest, resp)
Expand Down Expand Up @@ -940,7 +940,7 @@ func (a *RestAPI) UploadContainerObject(ctx echo.Context, containerID apiserver.
}

if needParseExpiration(filtered) {
epochDuration, err := getEpochDurations(ctx.Request().Context(), a.pool)
epochDuration, err := getEpochDurations(ctx.Request().Context(), a.networkInfoGetter)
if err != nil {
resp := a.logAndGetErrorResponse("could not get epoch durations from network info", err)
return ctx.JSON(http.StatusBadRequest, resp)
Expand Down
9 changes: 4 additions & 5 deletions handlers/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"github.com/nspcc-dev/neofs-sdk-go/container/acl"
"github.com/nspcc-dev/neofs-sdk-go/object"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/nspcc-dev/neofs-sdk-go/pool"
"github.com/nspcc-dev/neofs-sdk-go/session"
"go.uber.org/zap"
)
Expand Down Expand Up @@ -55,7 +54,7 @@ const (
limitDefault = 100
)

func getObjectAttributes(ctx context.Context, pool *pool.Pool, attrs []apiserver.Attribute, prm PrmAttributes) ([]object.Attribute, error) {
func getObjectAttributes(ctx context.Context, networkInfoGetter networkInfoGetter, attrs []apiserver.Attribute, prm PrmAttributes) ([]object.Attribute, error) {
headers := make(map[string]string, len(attrs))

for _, attr := range attrs {
Expand All @@ -64,7 +63,7 @@ func getObjectAttributes(ctx context.Context, pool *pool.Pool, attrs []apiserver
delete(headers, object.AttributeFileName)

if needParseExpiration(headers) {
epochDuration, err := getEpochDurations(ctx, pool)
epochDuration, err := getEpochDurations(ctx, networkInfoGetter)
if err != nil {
return nil, fmt.Errorf("could not get epoch durations from network info: %w", err)
}
Expand All @@ -91,8 +90,8 @@ func getObjectAttributes(ctx context.Context, pool *pool.Pool, attrs []apiserver
return attributes, nil
}

func getEpochDurations(ctx context.Context, p *pool.Pool) (*epochDurations, error) {
networkInfo, err := p.NetworkInfo(ctx, client.PrmNetworkInfo{})
func getEpochDurations(ctx context.Context, networkInfoGetter networkInfoGetter) (*epochDurations, error) {
networkInfo, err := networkInfoGetter.NetworkInfo(ctx)
if err != nil {
return nil, err
}
Expand Down
61 changes: 61 additions & 0 deletions internal/cache/networkinfo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package cache

import (
"context"
"fmt"
"sync"
"time"

"github.com/nspcc-dev/neofs-sdk-go/client"
"github.com/nspcc-dev/neofs-sdk-go/netmap"
"github.com/nspcc-dev/neofs-sdk-go/pool"
)

type (
// NetworkInfo is cache wrapper for the network info.
NetworkInfo struct {
p *pool.Pool
ttl time.Duration

mu *sync.Mutex
validUntil time.Time
ni netmap.NetworkInfo
}
)

func NewNetworkInfoCache(p *pool.Pool) *NetworkInfo {
return &NetworkInfo{
p: p,
mu: &sync.Mutex{},
}
}

func (n *NetworkInfo) NetworkInfo(ctx context.Context) (netmap.NetworkInfo, error) {
n.mu.Lock()
defer n.mu.Unlock()

if n.validUntil.After(time.Now()) {
return n.ni, nil
}

ni, err := n.p.NetworkInfo(ctx, client.PrmNetworkInfo{})
if err != nil {
return netmap.NetworkInfo{}, fmt.Errorf("get network info: %w", err)
}

n.update(ni)

return ni, nil
}

func (n *NetworkInfo) update(ni netmap.NetworkInfo) {
n.ttl = time.Duration(int64(ni.EpochDuration())/2*ni.MsPerBlock()) * time.Millisecond
n.validUntil = time.Now().Add(n.ttl)
n.ni = ni
}

func (n *NetworkInfo) StoreNetworkInfo(ni netmap.NetworkInfo) {
n.mu.Lock()
n.update(ni)
n.mu.Unlock()
}

0 comments on commit e1b12eb

Please sign in to comment.