From 157d3d980e83acf36d0c8c8812e6c6b3634e76f5 Mon Sep 17 00:00:00 2001 From: Yaroslav Vorobiov Date: Thu, 3 Jun 2021 14:52:28 +0300 Subject: [PATCH] multinode/console: storage usage and total storage usage Change-Id: I4970275daf4a4a9c5d02aea6a205891869dd4eff --- multinode/console/controllers/storage.go | 260 +++++++++++ multinode/console/server/server.go | 37 +- multinode/peer.go | 24 +- multinode/storage/service.go | 207 +++++++++ multinode/storage/storage.go | 55 +++ multinode/storage/storage_test.go | 152 ++++++ private/compensation/period.go | 63 +++ private/compensation/period_test.go | 42 ++ private/multinodepb/multinode.pb.go | 558 ++++++++++++++++------- private/multinodepb/multinode.proto | 28 ++ private/multinodepb/multinode_drpc.pb.go | 82 +++- storagenode/multinode/storage.go | 80 +++- storagenode/peer.go | 1 + 13 files changed, 1417 insertions(+), 172 deletions(-) create mode 100644 multinode/console/controllers/storage.go create mode 100644 multinode/storage/service.go create mode 100644 multinode/storage/storage.go create mode 100644 multinode/storage/storage_test.go create mode 100644 private/compensation/period.go create mode 100644 private/compensation/period_test.go diff --git a/multinode/console/controllers/storage.go b/multinode/console/controllers/storage.go new file mode 100644 index 000000000..01ee7a7b0 --- /dev/null +++ b/multinode/console/controllers/storage.go @@ -0,0 +1,260 @@ +// Copyright (C) 2021 Storj Labs, Inc. +// See LICENSE for copying information. + +package controllers + +import ( + "encoding/json" + "net/http" + "time" + + "github.com/gorilla/mux" + "github.com/zeebo/errs" + "go.uber.org/zap" + + "storj.io/common/storj" + "storj.io/storj/multinode/nodes" + "storj.io/storj/multinode/storage" + "storj.io/storj/private/compensation" +) + +var ( + // ErrStorage is an internal error type for storage web api controller. + ErrStorage = errs.Class("storage web api controller") +) + +// Storage is a storage web api controller. +type Storage struct { + log *zap.Logger + service *storage.Service +} + +// NewStorage is a constructor of Storage controller. +func NewStorage(log *zap.Logger, service *storage.Service) *Storage { + return &Storage{ + log: log, + service: service, + } +} + +// Usage handles retrieval of a node storage usage for a period interval. +func (storage *Storage) Usage(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + var err error + defer mon.Task()(&ctx)(&err) + + w.Header().Add("Content-Type", "application/json") + segments := mux.Vars(r) + + nodeIDEnc, ok := segments["nodeID"] + if !ok { + storage.serveError(w, http.StatusBadRequest, ErrStorage.New("could not receive node id segment")) + return + } + nodeID, err := storj.NodeIDFromString(nodeIDEnc) + if err != nil { + storage.serveError(w, http.StatusBadRequest, ErrStorage.Wrap(err)) + return + } + + var from time.Time + to := time.Now() + + if periodParam := r.URL.Query().Get("period"); periodParam != "" { + period, err := compensation.PeriodFromString(periodParam) + if err != nil { + storage.serveError(w, http.StatusBadRequest, ErrStorage.Wrap(err)) + return + } + + from = period.StartDate() + to = period.EndDateExclusive() + } + + usage, err := storage.service.Usage(ctx, nodeID, from, to) + if err != nil { + if nodes.ErrNoNode.Has(err) { + storage.serveError(w, http.StatusNotFound, ErrStorage.Wrap(err)) + return + } + + storage.log.Error("usage internal error", zap.Error(ErrStorage.Wrap(err))) + storage.serveError(w, http.StatusInternalServerError, ErrStorage.Wrap(err)) + return + } + + if err = json.NewEncoder(w).Encode(usage); err != nil { + storage.log.Error("failed to write json response", zap.Error(ErrStorage.Wrap(err))) + return + } +} + +// UsageSatellite handles retrieval of a node storage usage for a satellite and period interval. +func (storage *Storage) UsageSatellite(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + var err error + defer mon.Task()(&ctx)(&err) + + w.Header().Add("Content-Type", "application/json") + segments := mux.Vars(r) + + nodeIDEnc, ok := segments["nodeID"] + if !ok { + storage.serveError(w, http.StatusBadRequest, ErrStorage.New("could not receive node id segment")) + return + } + satelliteIDEnc, ok := segments["satelliteID"] + if !ok { + storage.serveError(w, http.StatusBadRequest, ErrStorage.New("could not receive satellite id segment")) + return + } + + nodeID, err := storj.NodeIDFromString(nodeIDEnc) + if err != nil { + storage.serveError(w, http.StatusBadRequest, ErrStorage.Wrap(err)) + return + } + satelliteID, err := storj.NodeIDFromString(satelliteIDEnc) + if err != nil { + storage.serveError(w, http.StatusBadRequest, ErrStorage.Wrap(err)) + return + } + + var from time.Time + to := time.Now() + + if periodParam := r.URL.Query().Get("period"); periodParam != "" { + period, err := compensation.PeriodFromString(periodParam) + if err != nil { + storage.serveError(w, http.StatusBadRequest, ErrStorage.Wrap(err)) + return + } + + from = period.StartDate() + to = period.EndDateExclusive() + } + + usage, err := storage.service.UsageSatellite(ctx, nodeID, satelliteID, from, to) + if err != nil { + if nodes.ErrNoNode.Has(err) { + storage.serveError(w, http.StatusNotFound, ErrStorage.Wrap(err)) + return + } + + storage.log.Error("usage satellite internal error", zap.Error(ErrStorage.Wrap(err))) + storage.serveError(w, http.StatusInternalServerError, ErrStorage.Wrap(err)) + return + } + + if err = json.NewEncoder(w).Encode(usage); err != nil { + storage.log.Error("failed to write json response", zap.Error(ErrStorage.Wrap(err))) + return + } +} + +// TotalUsage handles retrieval of aggregated storage usage for a period interval. +func (storage *Storage) TotalUsage(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + var err error + defer mon.Task()(&ctx)(&err) + + w.Header().Add("Content-Type", "application/json") + + var from time.Time + to := time.Now() + + if periodParam := r.URL.Query().Get("period"); periodParam != "" { + period, err := compensation.PeriodFromString(periodParam) + if err != nil { + storage.serveError(w, http.StatusBadRequest, ErrStorage.Wrap(err)) + return + } + + from = period.StartDate() + to = period.EndDateExclusive() + } + + usage, err := storage.service.TotalUsage(ctx, from, to) + if err != nil { + if nodes.ErrNoNode.Has(err) { + storage.serveError(w, http.StatusNotFound, ErrStorage.Wrap(err)) + return + } + + storage.log.Error("total usage internal error", zap.Error(ErrStorage.Wrap(err))) + storage.serveError(w, http.StatusInternalServerError, ErrStorage.Wrap(err)) + return + } + + if err = json.NewEncoder(w).Encode(usage); err != nil { + storage.log.Error("failed to write json response", zap.Error(ErrStorage.Wrap(err))) + return + } +} + +// TotalUsageSatellite handles retrieval of aggregated storage usage for a satellite and period interval. +func (storage *Storage) TotalUsageSatellite(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + var err error + defer mon.Task()(&ctx)(&err) + + w.Header().Add("Content-Type", "application/json") + segments := mux.Vars(r) + + satelliteIDEnc, ok := segments["satelliteID"] + if !ok { + storage.serveError(w, http.StatusBadRequest, ErrStorage.New("could not receive satellite id segment")) + return + } + satelliteID, err := storj.NodeIDFromString(satelliteIDEnc) + if err != nil { + storage.serveError(w, http.StatusBadRequest, ErrStorage.Wrap(err)) + return + } + + var from time.Time + to := time.Now() + + if periodParam := r.URL.Query().Get("period"); periodParam != "" { + period, err := compensation.PeriodFromString(periodParam) + if err != nil { + storage.serveError(w, http.StatusBadRequest, ErrStorage.Wrap(err)) + return + } + + from = period.StartDate() + to = period.EndDateExclusive() + } + + usage, err := storage.service.TotalUsageSatellite(ctx, satelliteID, from, to) + if err != nil { + if nodes.ErrNoNode.Has(err) { + storage.serveError(w, http.StatusNotFound, ErrStorage.Wrap(err)) + return + } + + storage.log.Error("usage satellite internal error", zap.Error(ErrStorage.Wrap(err))) + storage.serveError(w, http.StatusInternalServerError, ErrStorage.Wrap(err)) + return + } + + if err = json.NewEncoder(w).Encode(usage); err != nil { + storage.log.Error("failed to write json response", zap.Error(ErrStorage.Wrap(err))) + return + } +} + +// serveError set http statuses and send json error. +func (storage *Storage) serveError(w http.ResponseWriter, status int, err error) { + w.WriteHeader(status) + + var response struct { + Error string `json:"error"` + } + response.Error = err.Error() + + err = json.NewEncoder(w).Encode(response) + if err != nil { + storage.log.Error("failed to write json error response", zap.Error(err)) + } +} diff --git a/multinode/console/server/server.go b/multinode/console/server/server.go index d302793b3..d7f0d7dbe 100644 --- a/multinode/console/server/server.go +++ b/multinode/console/server/server.go @@ -19,6 +19,7 @@ import ( "storj.io/storj/multinode/nodes" "storj.io/storj/multinode/operators" "storj.io/storj/multinode/payouts" + "storj.io/storj/multinode/storage" ) var ( @@ -32,32 +33,41 @@ type Config struct { StaticDir string `help:"path to static resources" default:""` } +// Services contains services utilized by multinode dashboard. +type Services struct { + Nodes *nodes.Service + Payouts *payouts.Service + Operators *operators.Service + Storage *storage.Service +} + // Server represents Multinode Dashboard http server. // // architecture: Endpoint type Server struct { - log *zap.Logger + log *zap.Logger + listener net.Listener + http http.Server + config Config - config Config nodes *nodes.Service payouts *payouts.Service operators *operators.Service - - listener net.Listener - http http.Server + storage *storage.Service index *template.Template } // NewServer returns new instance of Multinode Dashboard http server. -func NewServer(log *zap.Logger, config Config, nodes *nodes.Service, payouts *payouts.Service, operators *operators.Service, listener net.Listener) (*Server, error) { +func NewServer(log *zap.Logger, listener net.Listener, config Config, services Services) (*Server, error) { server := Server{ log: log, - config: config, - nodes: nodes, - operators: operators, - payouts: payouts, listener: listener, + config: config, + nodes: services.Nodes, + operators: services.Operators, + payouts: services.Payouts, + storage: services.Storage, } router := mux.NewRouter() @@ -95,6 +105,13 @@ func NewServer(log *zap.Logger, config Config, nodes *nodes.Service, payouts *pa payoutsRouter.HandleFunc("/satellites/{id}/paystubs/{nodeID}", payoutsController.PaystubSatellite).Methods(http.MethodGet) payoutsRouter.HandleFunc("/satellites/{id}/paystubs/{period}/{nodeID}", payoutsController.PaystubSatellitePeriod).Methods(http.MethodGet) + storageController := controllers.NewStorage(server.log, server.storage) + storageRouter := apiRouter.PathPrefix("/storage").Subrouter() + storageRouter.HandleFunc("/usage", storageController.TotalUsage).Methods(http.MethodGet) + storageRouter.HandleFunc("/usage/{nodeID}", storageController.Usage).Methods(http.MethodGet) + storageRouter.HandleFunc("/satellites/{satelliteID}/usage", storageController.TotalUsageSatellite).Methods(http.MethodGet) + storageRouter.HandleFunc("/satellites/{satelliteID}/usage/{nodeID}", storageController.UsageSatellite).Methods(http.MethodGet) + if server.config.StaticDir != "" { router.PathPrefix("/static/").Handler(http.StripPrefix("/static", fs)) router.PathPrefix("/").HandlerFunc(server.appHandler) diff --git a/multinode/peer.go b/multinode/peer.go index 4ff24400a..962afe6f6 100644 --- a/multinode/peer.go +++ b/multinode/peer.go @@ -19,6 +19,7 @@ import ( "storj.io/storj/multinode/nodes" "storj.io/storj/multinode/operators" "storj.io/storj/multinode/payouts" + "storj.io/storj/multinode/storage" "storj.io/storj/private/lifecycle" ) @@ -73,6 +74,10 @@ type Peer struct { Service *payouts.Service } + Storage struct { + Service *storage.Service + } + // Web server with web UI. Console struct { Listener net.Listener @@ -127,6 +132,14 @@ func New(log *zap.Logger, full *identity.FullIdentity, config Config, db DB) (_ ) } + { // storage setup + peer.Storage.Service = storage.NewService( + peer.Log.Named("storage:service"), + peer.Dialer, + peer.DB.Nodes(), + ) + } + { // console setup peer.Console.Listener, err = net.Listen("tcp", config.Console.Address) if err != nil { @@ -135,11 +148,14 @@ func New(log *zap.Logger, full *identity.FullIdentity, config Config, db DB) (_ peer.Console.Endpoint, err = server.NewServer( peer.Log.Named("console:endpoint"), - config.Console, - peer.Nodes.Service, - peer.Payouts.Service, - peer.Operators.Service, peer.Console.Listener, + config.Console, + server.Services{ + Nodes: peer.Nodes.Service, + Payouts: peer.Payouts.Service, + Operators: peer.Operators.Service, + Storage: peer.Storage.Service, + }, ) if err != nil { return nil, err diff --git a/multinode/storage/service.go b/multinode/storage/service.go new file mode 100644 index 000000000..f6ad8ddda --- /dev/null +++ b/multinode/storage/service.go @@ -0,0 +1,207 @@ +// Copyright (C) 2021 Storj Labs, Inc. +// See LICENSE for copying information. + +package storage + +import ( + "context" + "time" + + "github.com/spacemonkeygo/monkit/v3" + "github.com/zeebo/errs" + "go.uber.org/zap" + + "storj.io/common/rpc" + "storj.io/common/storj" + "storj.io/storj/multinode/nodes" + "storj.io/storj/private/multinodepb" +) + +var ( + mon = monkit.Package() + // Error is an error class for storage service error. + Error = errs.Class("storage") +) + +// Service exposes all storage related logic. +// +// architecture: Service +type Service struct { + log *zap.Logger + dialer rpc.Dialer + nodes nodes.DB +} + +// NewService creates new instance of Service. +func NewService(log *zap.Logger, dialer rpc.Dialer, nodes nodes.DB) *Service { + return &Service{ + log: log, + dialer: dialer, + nodes: nodes, + } +} + +// Usage retrieves node's daily storage usage for provided interval. +func (service *Service) Usage(ctx context.Context, nodeID storj.NodeID, from, to time.Time) (_ []UsageStamp, err error) { + defer mon.Task()(&ctx)(&err) + + node, err := service.nodes.Get(ctx, nodeID) + if err != nil { + return nil, Error.Wrap(err) + } + + stamps, err := service.dialUsage(ctx, node, from, to) + if err != nil { + return nil, Error.Wrap(err) + } + + return stamps, nil +} + +// UsageSatellite retrieves node's daily storage usage for provided interval and satellite. +func (service *Service) UsageSatellite(ctx context.Context, nodeID, satelliteID storj.NodeID, from, to time.Time) (_ []UsageStamp, err error) { + defer mon.Task()(&ctx)(&err) + + node, err := service.nodes.Get(ctx, nodeID) + if err != nil { + return nil, Error.Wrap(err) + } + + stamps, err := service.dialUsageSatellite(ctx, node, satelliteID, from, to) + if err != nil { + return nil, Error.Wrap(err) + } + + return stamps, nil +} + +// TotalUsage retrieves aggregated daily storage usage for provided interval. +func (service *Service) TotalUsage(ctx context.Context, from, to time.Time) (_ []UsageStamp, err error) { + defer mon.Task()(&ctx)(&err) + + nodesList, err := service.nodes.List(ctx) + if err != nil { + return nil, Error.Wrap(err) + } + + cache := make(UsageStampDailyCache) + + for _, node := range nodesList { + stamps, err := service.dialUsage(ctx, node, from, to) + if err != nil { + return nil, Error.Wrap(err) + } + + for _, stamp := range stamps { + cache.Add(stamp) + } + } + + return cache.Sorted(), nil +} + +// TotalUsageSatellite retrieves aggregated daily storage usage for provided interval and satellite. +func (service *Service) TotalUsageSatellite(ctx context.Context, satelliteID storj.NodeID, from, to time.Time) (_ []UsageStamp, err error) { + defer mon.Task()(&ctx)(&err) + + nodesList, err := service.nodes.List(ctx) + if err != nil { + return nil, Error.Wrap(err) + } + + cache := make(UsageStampDailyCache) + + for _, node := range nodesList { + stamps, err := service.dialUsageSatellite(ctx, node, satelliteID, from, to) + if err != nil { + return nil, Error.Wrap(err) + } + + for _, stamp := range stamps { + cache.Add(stamp) + } + } + + return cache.Sorted(), nil +} + +// dialUsage dials node and retrieves it's storage usage for provided interval. +func (service *Service) dialUsage(ctx context.Context, node nodes.Node, from, to time.Time) (_ []UsageStamp, err error) { + defer mon.Task()(&ctx)(&err) + + conn, err := service.dialer.DialNodeURL(ctx, storj.NodeURL{ + ID: node.ID, + Address: node.PublicAddress, + }) + if err != nil { + return nil, Error.Wrap(err) + } + defer func() { + err = errs.Combine(err, conn.Close()) + }() + + storageClient := multinodepb.NewDRPCStorageClient(conn) + + req := &multinodepb.StorageUsageRequest{ + Header: &multinodepb.RequestHeader{ + ApiKey: node.APISecret, + }, + From: from, + To: to, + } + resp, err := storageClient.Usage(ctx, req) + if err != nil { + return nil, Error.Wrap(err) + } + + var stamps []UsageStamp + for _, usage := range resp.GetStorageUsage() { + stamps = append(stamps, UsageStamp{ + AtRestTotal: usage.GetAtRestTotal(), + IntervalStart: usage.GetIntervalStart(), + }) + } + + return stamps, nil +} + +// dialUsageSatellite dials node and retrieves it's storage usage for provided interval and satellite. +func (service *Service) dialUsageSatellite(ctx context.Context, node nodes.Node, satelliteID storj.NodeID, from, to time.Time) (_ []UsageStamp, err error) { + defer mon.Task()(&ctx)(&err) + + conn, err := service.dialer.DialNodeURL(ctx, storj.NodeURL{ + ID: node.ID, + Address: node.PublicAddress, + }) + if err != nil { + return nil, Error.Wrap(err) + } + defer func() { + err = errs.Combine(err, conn.Close()) + }() + + storageClient := multinodepb.NewDRPCStorageClient(conn) + + req := &multinodepb.StorageUsageSatelliteRequest{ + Header: &multinodepb.RequestHeader{ + ApiKey: node.APISecret, + }, + SatelliteId: satelliteID, + From: from, + To: to, + } + resp, err := storageClient.UsageSatellite(ctx, req) + if err != nil { + return nil, Error.Wrap(err) + } + + var stamps []UsageStamp + for _, usage := range resp.GetStorageUsage() { + stamps = append(stamps, UsageStamp{ + AtRestTotal: usage.GetAtRestTotal(), + IntervalStart: usage.GetIntervalStart(), + }) + } + + return stamps, nil +} diff --git a/multinode/storage/storage.go b/multinode/storage/storage.go new file mode 100644 index 000000000..3af125ec6 --- /dev/null +++ b/multinode/storage/storage.go @@ -0,0 +1,55 @@ +// Copyright (C) 2021 Storj Labs, Inc. +// See LICENSE for copying information. + +package storage + +import ( + "sort" + "time" +) + +// UsageStamp holds data at rest total for an interval beginning at interval start. +type UsageStamp struct { + AtRestTotal float64 + IntervalStart time.Time +} + +// UsageStampDailyCache caches storage usage stamps by interval date. +type UsageStampDailyCache map[time.Time]UsageStamp + +// Add adds usage stamp to cache aggregating at rest data by date. +func (cache *UsageStampDailyCache) Add(stamp UsageStamp) { + year, month, day := stamp.IntervalStart.UTC().Date() + intervalStart := time.Date(year, month, day, 0, 0, 0, 0, time.UTC) + + cached := *cache + + cacheStamp, ok := cached[intervalStart] + if ok { + cached[intervalStart] = UsageStamp{ + AtRestTotal: cacheStamp.AtRestTotal + stamp.AtRestTotal, + IntervalStart: intervalStart, + } + } else { + cached[intervalStart] = UsageStamp{ + AtRestTotal: stamp.AtRestTotal, + IntervalStart: intervalStart, + } + } + + *cache = cached +} + +// Sorted returns usage stamp slice sorted by interval start. +func (cache *UsageStampDailyCache) Sorted() []UsageStamp { + var usage []UsageStamp + + for _, stamp := range *cache { + usage = append(usage, stamp) + } + sort.Slice(usage, func(i, j int) bool { + return usage[i].IntervalStart.Before(usage[j].IntervalStart) + }) + + return usage +} diff --git a/multinode/storage/storage_test.go b/multinode/storage/storage_test.go new file mode 100644 index 000000000..9b1cea838 --- /dev/null +++ b/multinode/storage/storage_test.go @@ -0,0 +1,152 @@ +// Copyright (C) 2021 Storj Labs, Inc. +// See LICENSE for copying information. + +package storage_test + +import ( + "testing" + "time" + + "github.com/stretchr/testify/require" + + "storj.io/storj/multinode/storage" +) + +func TestUsageStampDailyCache(t *testing.T) { + newTimestamp := func(month time.Month, day, hour int) time.Time { + return time.Date(2021, month, day, hour, 0, 0, 0, time.UTC) + } + + testData := []struct { + Date time.Time + AtRest []float64 + Hours []int + }{ + { + Date: newTimestamp(time.May, 1, 0), + AtRest: []float64{2, 3}, + Hours: []int{1, 0}, + }, + { + Date: newTimestamp(time.May, 2, 0), + AtRest: []float64{1, 2, 3}, + Hours: []int{0, 1, 0}, + }, + { + Date: newTimestamp(time.May, 3, 0), + AtRest: []float64{1, 2, 3}, + Hours: []int{0, 1, 0}, + }, + { + Date: newTimestamp(time.May, 4, 0), + AtRest: []float64{1, 2, 3}, + Hours: []int{0, 1, 0}, + }, + { + Date: newTimestamp(time.May, 5, 0), + AtRest: []float64{1, 2, 3}, + Hours: []int{0, 1, 0}, + }, + { + Date: newTimestamp(time.May, 6, 0), + AtRest: []float64{1, 2, 3}, + Hours: []int{0, 1, 0}, + }, + { + Date: newTimestamp(time.May, 7, 0), + AtRest: []float64{1, 2, 3}, + Hours: []int{0, 1, 0}, + }, + { + Date: newTimestamp(time.May, 8, 0), + AtRest: []float64{1, 2, 3}, + Hours: []int{0, 1, 0}, + }, + { + Date: newTimestamp(time.May, 9, 0), + AtRest: []float64{1, 2, 3}, + Hours: []int{0, 1, 0}, + }, + { + Date: newTimestamp(time.May, 10, 0), + AtRest: []float64{1, 2, 3}, + Hours: []int{0, 1, 0}, + }, + { + Date: newTimestamp(time.May, 11, 0), + AtRest: []float64{1, 2}, + Hours: []int{0, 1}, + }, + { + Date: newTimestamp(time.May, 12, 0), + AtRest: []float64{1, 2}, + Hours: []int{0, 1}, + }, + } + + expected := []storage.UsageStamp{ + { + IntervalStart: newTimestamp(time.May, 1, 0), + AtRestTotal: 5, + }, + { + IntervalStart: newTimestamp(time.May, 2, 0), + AtRestTotal: 6, + }, + { + IntervalStart: newTimestamp(time.May, 3, 0), + AtRestTotal: 6, + }, + { + IntervalStart: newTimestamp(time.May, 4, 0), + AtRestTotal: 6, + }, + { + IntervalStart: newTimestamp(time.May, 5, 0), + AtRestTotal: 6, + }, + { + IntervalStart: newTimestamp(time.May, 6, 0), + AtRestTotal: 6, + }, + { + IntervalStart: newTimestamp(time.May, 7, 0), + AtRestTotal: 6, + }, + { + IntervalStart: newTimestamp(time.May, 8, 0), + AtRestTotal: 6, + }, + { + IntervalStart: newTimestamp(time.May, 9, 0), + AtRestTotal: 6, + }, + { + IntervalStart: newTimestamp(time.May, 10, 0), + AtRestTotal: 6, + }, + { + IntervalStart: newTimestamp(time.May, 11, 0), + AtRestTotal: 3, + }, + { + IntervalStart: newTimestamp(time.May, 12, 0), + AtRestTotal: 3, + }, + } + + cache := make(storage.UsageStampDailyCache) + for _, entry := range testData { + _, month, day := entry.Date.Date() + + for i, atRest := range entry.AtRest { + cache.Add(storage.UsageStamp{ + AtRestTotal: atRest, + IntervalStart: newTimestamp(month, day, entry.Hours[i]), + }) + } + } + + stamps := cache.Sorted() + require.Equal(t, expected, stamps) +} diff --git a/private/compensation/period.go b/private/compensation/period.go new file mode 100644 index 000000000..e84af465e --- /dev/null +++ b/private/compensation/period.go @@ -0,0 +1,63 @@ +// Copyright (C) 2021 Storj Labs, Inc. +// See LICENSE for copying information. + +package compensation + +import ( + "fmt" + "time" +) + +// Period represents a monthly payment period. +type Period struct { + Year int + Month time.Month +} + +// String outputs the YYYY-MM form of the payment period. +func (p Period) String() string { + return fmt.Sprintf("%04d-%02d", p.Year, p.Month) +} + +// StartDate returns a time.Time that is less than or equal to any time in the period. +func (p Period) StartDate() time.Time { + return time.Date(p.Year, p.Month, 1, 0, 0, 0, 0, time.UTC) +} + +// EndDateExclusive returns a time.Time that is greater than any time in the period. +func (p Period) EndDateExclusive() time.Time { + return time.Date(p.Year, p.Month+1, 1, 0, 0, 0, 0, time.UTC) +} + +// UnmarshalCSV reads the Period in CSV form. +func (p *Period) UnmarshalCSV(s string) error { + v, err := PeriodFromString(s) + if err != nil { + return err + } + *p = v + return nil +} + +// MarshalCSV returns the CSV form of the Period. +func (p Period) MarshalCSV() (string, error) { + return p.String(), nil +} + +// PeriodFromString parses the YYYY-MM string into a Period. +func PeriodFromString(s string) (Period, error) { + t, err := time.Parse("2006-01", s) + if err != nil { + return Period{}, err + } + return PeriodFromTime(t), nil +} + +// PeriodFromTime takes a time.Time and returns a Period that contains it. +func PeriodFromTime(t time.Time) Period { + year, month, _ := t.UTC().Date() + return Period{ + Year: year, + Month: month, + } +} diff --git a/private/compensation/period_test.go b/private/compensation/period_test.go new file mode 100644 index 000000000..21493988b --- /dev/null +++ b/private/compensation/period_test.go @@ -0,0 +1,42 @@ +// Copyright (C) 2021 Storj Labs, Inc. +// See LICENSE for copying information. + +package compensation + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestPeriod(t *testing.T) { + for _, tt := range []struct { + year int + month time.Month + startDate string + endDate string + days int + }{ + {year: 2019, month: 1, startDate: "2019-01-01", endDate: "2019-02-01", days: 31}, + {year: 2019, month: 2, startDate: "2019-02-01", endDate: "2019-03-01", days: 28}, + {year: 2019, month: 3, startDate: "2019-03-01", endDate: "2019-04-01", days: 31}, + {year: 2019, month: 4, startDate: "2019-04-01", endDate: "2019-05-01", days: 30}, + {year: 2019, month: 5, startDate: "2019-05-01", endDate: "2019-06-01", days: 31}, + {year: 2019, month: 6, startDate: "2019-06-01", endDate: "2019-07-01", days: 30}, + {year: 2019, month: 7, startDate: "2019-07-01", endDate: "2019-08-01", days: 31}, + {year: 2019, month: 8, startDate: "2019-08-01", endDate: "2019-09-01", days: 31}, + {year: 2019, month: 9, startDate: "2019-09-01", endDate: "2019-10-01", days: 30}, + {year: 2019, month: 10, startDate: "2019-10-01", endDate: "2019-11-01", days: 31}, + {year: 2019, month: 11, startDate: "2019-11-01", endDate: "2019-12-01", days: 30}, + {year: 2019, month: 12, startDate: "2019-12-01", endDate: "2020-01-01", days: 31}, + // leap year/month + {year: 2020, month: 2, startDate: "2020-02-01", endDate: "2020-03-01", days: 29}, + } { + t.Logf("year:%d month:%d startDate:%s endDate:%s days:%d", tt.year, tt.month, tt.startDate, tt.endDate, tt.days) + + period := Period{Year: tt.year, Month: tt.month} + assert.Equal(t, tt.startDate, period.StartDate().Format("2006-01-02")) + assert.Equal(t, tt.endDate, period.EndDateExclusive().Format("2006-01-02")) + } +} diff --git a/private/multinodepb/multinode.pb.go b/private/multinodepb/multinode.pb.go index 183721390..9a0fd3314 100644 --- a/private/multinodepb/multinode.pb.go +++ b/private/multinodepb/multinode.pb.go @@ -177,6 +177,237 @@ func (m *DiskSpaceResponse) GetOverused() int64 { return 0 } +type StorageUsage struct { + AtRestTotal float64 `protobuf:"fixed64,1,opt,name=at_rest_total,json=atRestTotal,proto3" json:"at_rest_total,omitempty"` + IntervalStart time.Time `protobuf:"bytes,2,opt,name=interval_start,json=intervalStart,proto3,stdtime" json:"interval_start"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StorageUsage) Reset() { *m = StorageUsage{} } +func (m *StorageUsage) String() string { return proto.CompactTextString(m) } +func (*StorageUsage) ProtoMessage() {} +func (*StorageUsage) Descriptor() ([]byte, []int) { + return fileDescriptor_9a45fd79b06f3a1b, []int{3} +} +func (m *StorageUsage) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StorageUsage.Unmarshal(m, b) +} +func (m *StorageUsage) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StorageUsage.Marshal(b, m, deterministic) +} +func (m *StorageUsage) XXX_Merge(src proto.Message) { + xxx_messageInfo_StorageUsage.Merge(m, src) +} +func (m *StorageUsage) XXX_Size() int { + return xxx_messageInfo_StorageUsage.Size(m) +} +func (m *StorageUsage) XXX_DiscardUnknown() { + xxx_messageInfo_StorageUsage.DiscardUnknown(m) +} + +var xxx_messageInfo_StorageUsage proto.InternalMessageInfo + +func (m *StorageUsage) GetAtRestTotal() float64 { + if m != nil { + return m.AtRestTotal + } + return 0 +} + +func (m *StorageUsage) GetIntervalStart() time.Time { + if m != nil { + return m.IntervalStart + } + return time.Time{} +} + +type StorageUsageRequest struct { + Header *RequestHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` + From time.Time `protobuf:"bytes,2,opt,name=from,proto3,stdtime" json:"from"` + To time.Time `protobuf:"bytes,3,opt,name=to,proto3,stdtime" json:"to"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StorageUsageRequest) Reset() { *m = StorageUsageRequest{} } +func (m *StorageUsageRequest) String() string { return proto.CompactTextString(m) } +func (*StorageUsageRequest) ProtoMessage() {} +func (*StorageUsageRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9a45fd79b06f3a1b, []int{4} +} +func (m *StorageUsageRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StorageUsageRequest.Unmarshal(m, b) +} +func (m *StorageUsageRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StorageUsageRequest.Marshal(b, m, deterministic) +} +func (m *StorageUsageRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_StorageUsageRequest.Merge(m, src) +} +func (m *StorageUsageRequest) XXX_Size() int { + return xxx_messageInfo_StorageUsageRequest.Size(m) +} +func (m *StorageUsageRequest) XXX_DiscardUnknown() { + xxx_messageInfo_StorageUsageRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_StorageUsageRequest proto.InternalMessageInfo + +func (m *StorageUsageRequest) GetHeader() *RequestHeader { + if m != nil { + return m.Header + } + return nil +} + +func (m *StorageUsageRequest) GetFrom() time.Time { + if m != nil { + return m.From + } + return time.Time{} +} + +func (m *StorageUsageRequest) GetTo() time.Time { + if m != nil { + return m.To + } + return time.Time{} +} + +type StorageUsageResponse struct { + StorageUsage []*StorageUsage `protobuf:"bytes,1,rep,name=storage_usage,json=storageUsage,proto3" json:"storage_usage,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StorageUsageResponse) Reset() { *m = StorageUsageResponse{} } +func (m *StorageUsageResponse) String() string { return proto.CompactTextString(m) } +func (*StorageUsageResponse) ProtoMessage() {} +func (*StorageUsageResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9a45fd79b06f3a1b, []int{5} +} +func (m *StorageUsageResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StorageUsageResponse.Unmarshal(m, b) +} +func (m *StorageUsageResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StorageUsageResponse.Marshal(b, m, deterministic) +} +func (m *StorageUsageResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_StorageUsageResponse.Merge(m, src) +} +func (m *StorageUsageResponse) XXX_Size() int { + return xxx_messageInfo_StorageUsageResponse.Size(m) +} +func (m *StorageUsageResponse) XXX_DiscardUnknown() { + xxx_messageInfo_StorageUsageResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_StorageUsageResponse proto.InternalMessageInfo + +func (m *StorageUsageResponse) GetStorageUsage() []*StorageUsage { + if m != nil { + return m.StorageUsage + } + return nil +} + +type StorageUsageSatelliteRequest struct { + Header *RequestHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` + SatelliteId NodeID `protobuf:"bytes,2,opt,name=satellite_id,json=satelliteId,proto3,customtype=NodeID" json:"satellite_id"` + From time.Time `protobuf:"bytes,3,opt,name=from,proto3,stdtime" json:"from"` + To time.Time `protobuf:"bytes,4,opt,name=to,proto3,stdtime" json:"to"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StorageUsageSatelliteRequest) Reset() { *m = StorageUsageSatelliteRequest{} } +func (m *StorageUsageSatelliteRequest) String() string { return proto.CompactTextString(m) } +func (*StorageUsageSatelliteRequest) ProtoMessage() {} +func (*StorageUsageSatelliteRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_9a45fd79b06f3a1b, []int{6} +} +func (m *StorageUsageSatelliteRequest) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StorageUsageSatelliteRequest.Unmarshal(m, b) +} +func (m *StorageUsageSatelliteRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StorageUsageSatelliteRequest.Marshal(b, m, deterministic) +} +func (m *StorageUsageSatelliteRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_StorageUsageSatelliteRequest.Merge(m, src) +} +func (m *StorageUsageSatelliteRequest) XXX_Size() int { + return xxx_messageInfo_StorageUsageSatelliteRequest.Size(m) +} +func (m *StorageUsageSatelliteRequest) XXX_DiscardUnknown() { + xxx_messageInfo_StorageUsageSatelliteRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_StorageUsageSatelliteRequest proto.InternalMessageInfo + +func (m *StorageUsageSatelliteRequest) GetHeader() *RequestHeader { + if m != nil { + return m.Header + } + return nil +} + +func (m *StorageUsageSatelliteRequest) GetFrom() time.Time { + if m != nil { + return m.From + } + return time.Time{} +} + +func (m *StorageUsageSatelliteRequest) GetTo() time.Time { + if m != nil { + return m.To + } + return time.Time{} +} + +type StorageUsageSatelliteResponse struct { + StorageUsage []*StorageUsage `protobuf:"bytes,1,rep,name=storage_usage,json=storageUsage,proto3" json:"storage_usage,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` +} + +func (m *StorageUsageSatelliteResponse) Reset() { *m = StorageUsageSatelliteResponse{} } +func (m *StorageUsageSatelliteResponse) String() string { return proto.CompactTextString(m) } +func (*StorageUsageSatelliteResponse) ProtoMessage() {} +func (*StorageUsageSatelliteResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_9a45fd79b06f3a1b, []int{7} +} +func (m *StorageUsageSatelliteResponse) XXX_Unmarshal(b []byte) error { + return xxx_messageInfo_StorageUsageSatelliteResponse.Unmarshal(m, b) +} +func (m *StorageUsageSatelliteResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + return xxx_messageInfo_StorageUsageSatelliteResponse.Marshal(b, m, deterministic) +} +func (m *StorageUsageSatelliteResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_StorageUsageSatelliteResponse.Merge(m, src) +} +func (m *StorageUsageSatelliteResponse) XXX_Size() int { + return xxx_messageInfo_StorageUsageSatelliteResponse.Size(m) +} +func (m *StorageUsageSatelliteResponse) XXX_DiscardUnknown() { + xxx_messageInfo_StorageUsageSatelliteResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_StorageUsageSatelliteResponse proto.InternalMessageInfo + +func (m *StorageUsageSatelliteResponse) GetStorageUsage() []*StorageUsage { + if m != nil { + return m.StorageUsage + } + return nil +} + type BandwidthMonthSummaryRequest struct { Header *RequestHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"` XXX_NoUnkeyedLiteral struct{} `json:"-"` @@ -188,7 +419,7 @@ func (m *BandwidthMonthSummaryRequest) Reset() { *m = BandwidthMonthSumm func (m *BandwidthMonthSummaryRequest) String() string { return proto.CompactTextString(m) } func (*BandwidthMonthSummaryRequest) ProtoMessage() {} func (*BandwidthMonthSummaryRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{3} + return fileDescriptor_9a45fd79b06f3a1b, []int{8} } func (m *BandwidthMonthSummaryRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BandwidthMonthSummaryRequest.Unmarshal(m, b) @@ -226,7 +457,7 @@ func (m *BandwidthMonthSummaryResponse) Reset() { *m = BandwidthMonthSum func (m *BandwidthMonthSummaryResponse) String() string { return proto.CompactTextString(m) } func (*BandwidthMonthSummaryResponse) ProtoMessage() {} func (*BandwidthMonthSummaryResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{4} + return fileDescriptor_9a45fd79b06f3a1b, []int{9} } func (m *BandwidthMonthSummaryResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_BandwidthMonthSummaryResponse.Unmarshal(m, b) @@ -264,7 +495,7 @@ func (m *VersionRequest) Reset() { *m = VersionRequest{} } func (m *VersionRequest) String() string { return proto.CompactTextString(m) } func (*VersionRequest) ProtoMessage() {} func (*VersionRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{5} + return fileDescriptor_9a45fd79b06f3a1b, []int{10} } func (m *VersionRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VersionRequest.Unmarshal(m, b) @@ -302,7 +533,7 @@ func (m *VersionResponse) Reset() { *m = VersionResponse{} } func (m *VersionResponse) String() string { return proto.CompactTextString(m) } func (*VersionResponse) ProtoMessage() {} func (*VersionResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{6} + return fileDescriptor_9a45fd79b06f3a1b, []int{11} } func (m *VersionResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_VersionResponse.Unmarshal(m, b) @@ -340,7 +571,7 @@ func (m *LastContactRequest) Reset() { *m = LastContactRequest{} } func (m *LastContactRequest) String() string { return proto.CompactTextString(m) } func (*LastContactRequest) ProtoMessage() {} func (*LastContactRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{7} + return fileDescriptor_9a45fd79b06f3a1b, []int{12} } func (m *LastContactRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LastContactRequest.Unmarshal(m, b) @@ -378,7 +609,7 @@ func (m *LastContactResponse) Reset() { *m = LastContactResponse{} } func (m *LastContactResponse) String() string { return proto.CompactTextString(m) } func (*LastContactResponse) ProtoMessage() {} func (*LastContactResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{8} + return fileDescriptor_9a45fd79b06f3a1b, []int{13} } func (m *LastContactResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_LastContactResponse.Unmarshal(m, b) @@ -417,7 +648,7 @@ func (m *ReputationRequest) Reset() { *m = ReputationRequest{} } func (m *ReputationRequest) String() string { return proto.CompactTextString(m) } func (*ReputationRequest) ProtoMessage() {} func (*ReputationRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{9} + return fileDescriptor_9a45fd79b06f3a1b, []int{14} } func (m *ReputationRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ReputationRequest.Unmarshal(m, b) @@ -456,7 +687,7 @@ func (m *ReputationResponse) Reset() { *m = ReputationResponse{} } func (m *ReputationResponse) String() string { return proto.CompactTextString(m) } func (*ReputationResponse) ProtoMessage() {} func (*ReputationResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{10} + return fileDescriptor_9a45fd79b06f3a1b, []int{15} } func (m *ReputationResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ReputationResponse.Unmarshal(m, b) @@ -501,7 +732,7 @@ func (m *ReputationResponse_Online) Reset() { *m = ReputationResponse_On func (m *ReputationResponse_Online) String() string { return proto.CompactTextString(m) } func (*ReputationResponse_Online) ProtoMessage() {} func (*ReputationResponse_Online) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{10, 0} + return fileDescriptor_9a45fd79b06f3a1b, []int{15, 0} } func (m *ReputationResponse_Online) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ReputationResponse_Online.Unmarshal(m, b) @@ -540,7 +771,7 @@ func (m *ReputationResponse_Audit) Reset() { *m = ReputationResponse_Aud func (m *ReputationResponse_Audit) String() string { return proto.CompactTextString(m) } func (*ReputationResponse_Audit) ProtoMessage() {} func (*ReputationResponse_Audit) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{10, 1} + return fileDescriptor_9a45fd79b06f3a1b, []int{15, 1} } func (m *ReputationResponse_Audit) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_ReputationResponse_Audit.Unmarshal(m, b) @@ -585,7 +816,7 @@ func (m *TrustedSatellitesRequest) Reset() { *m = TrustedSatellitesReque func (m *TrustedSatellitesRequest) String() string { return proto.CompactTextString(m) } func (*TrustedSatellitesRequest) ProtoMessage() {} func (*TrustedSatellitesRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{11} + return fileDescriptor_9a45fd79b06f3a1b, []int{16} } func (m *TrustedSatellitesRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TrustedSatellitesRequest.Unmarshal(m, b) @@ -623,7 +854,7 @@ func (m *TrustedSatellitesResponse) Reset() { *m = TrustedSatellitesResp func (m *TrustedSatellitesResponse) String() string { return proto.CompactTextString(m) } func (*TrustedSatellitesResponse) ProtoMessage() {} func (*TrustedSatellitesResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{12} + return fileDescriptor_9a45fd79b06f3a1b, []int{17} } func (m *TrustedSatellitesResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TrustedSatellitesResponse.Unmarshal(m, b) @@ -662,7 +893,7 @@ func (m *TrustedSatellitesResponse_NodeURL) Reset() { *m = TrustedSatell func (m *TrustedSatellitesResponse_NodeURL) String() string { return proto.CompactTextString(m) } func (*TrustedSatellitesResponse_NodeURL) ProtoMessage() {} func (*TrustedSatellitesResponse_NodeURL) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{12, 0} + return fileDescriptor_9a45fd79b06f3a1b, []int{17, 0} } func (m *TrustedSatellitesResponse_NodeURL) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_TrustedSatellitesResponse_NodeURL.Unmarshal(m, b) @@ -700,7 +931,7 @@ func (m *OperatorRequest) Reset() { *m = OperatorRequest{} } func (m *OperatorRequest) String() string { return proto.CompactTextString(m) } func (*OperatorRequest) ProtoMessage() {} func (*OperatorRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{13} + return fileDescriptor_9a45fd79b06f3a1b, []int{18} } func (m *OperatorRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_OperatorRequest.Unmarshal(m, b) @@ -740,7 +971,7 @@ func (m *OperatorResponse) Reset() { *m = OperatorResponse{} } func (m *OperatorResponse) String() string { return proto.CompactTextString(m) } func (*OperatorResponse) ProtoMessage() {} func (*OperatorResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{14} + return fileDescriptor_9a45fd79b06f3a1b, []int{19} } func (m *OperatorResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_OperatorResponse.Unmarshal(m, b) @@ -793,7 +1024,7 @@ func (m *EstimatedPayoutSatelliteRequest) Reset() { *m = EstimatedPayout func (m *EstimatedPayoutSatelliteRequest) String() string { return proto.CompactTextString(m) } func (*EstimatedPayoutSatelliteRequest) ProtoMessage() {} func (*EstimatedPayoutSatelliteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{15} + return fileDescriptor_9a45fd79b06f3a1b, []int{20} } func (m *EstimatedPayoutSatelliteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EstimatedPayoutSatelliteRequest.Unmarshal(m, b) @@ -831,7 +1062,7 @@ func (m *EstimatedPayoutSatelliteResponse) Reset() { *m = EstimatedPayou func (m *EstimatedPayoutSatelliteResponse) String() string { return proto.CompactTextString(m) } func (*EstimatedPayoutSatelliteResponse) ProtoMessage() {} func (*EstimatedPayoutSatelliteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{16} + return fileDescriptor_9a45fd79b06f3a1b, []int{21} } func (m *EstimatedPayoutSatelliteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EstimatedPayoutSatelliteResponse.Unmarshal(m, b) @@ -869,7 +1100,7 @@ func (m *EstimatedPayoutRequest) Reset() { *m = EstimatedPayoutRequest{} func (m *EstimatedPayoutRequest) String() string { return proto.CompactTextString(m) } func (*EstimatedPayoutRequest) ProtoMessage() {} func (*EstimatedPayoutRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{17} + return fileDescriptor_9a45fd79b06f3a1b, []int{22} } func (m *EstimatedPayoutRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EstimatedPayoutRequest.Unmarshal(m, b) @@ -907,7 +1138,7 @@ func (m *EstimatedPayoutResponse) Reset() { *m = EstimatedPayoutResponse func (m *EstimatedPayoutResponse) String() string { return proto.CompactTextString(m) } func (*EstimatedPayoutResponse) ProtoMessage() {} func (*EstimatedPayoutResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{18} + return fileDescriptor_9a45fd79b06f3a1b, []int{23} } func (m *EstimatedPayoutResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EstimatedPayoutResponse.Unmarshal(m, b) @@ -945,7 +1176,7 @@ func (m *SummaryRequest) Reset() { *m = SummaryRequest{} } func (m *SummaryRequest) String() string { return proto.CompactTextString(m) } func (*SummaryRequest) ProtoMessage() {} func (*SummaryRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{19} + return fileDescriptor_9a45fd79b06f3a1b, []int{24} } func (m *SummaryRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SummaryRequest.Unmarshal(m, b) @@ -983,7 +1214,7 @@ func (m *SummaryResponse) Reset() { *m = SummaryResponse{} } func (m *SummaryResponse) String() string { return proto.CompactTextString(m) } func (*SummaryResponse) ProtoMessage() {} func (*SummaryResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{20} + return fileDescriptor_9a45fd79b06f3a1b, []int{25} } func (m *SummaryResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SummaryResponse.Unmarshal(m, b) @@ -1022,7 +1253,7 @@ func (m *SummaryPeriodRequest) Reset() { *m = SummaryPeriodRequest{} } func (m *SummaryPeriodRequest) String() string { return proto.CompactTextString(m) } func (*SummaryPeriodRequest) ProtoMessage() {} func (*SummaryPeriodRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{21} + return fileDescriptor_9a45fd79b06f3a1b, []int{26} } func (m *SummaryPeriodRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SummaryPeriodRequest.Unmarshal(m, b) @@ -1067,7 +1298,7 @@ func (m *SummaryPeriodResponse) Reset() { *m = SummaryPeriodResponse{} } func (m *SummaryPeriodResponse) String() string { return proto.CompactTextString(m) } func (*SummaryPeriodResponse) ProtoMessage() {} func (*SummaryPeriodResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{22} + return fileDescriptor_9a45fd79b06f3a1b, []int{27} } func (m *SummaryPeriodResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SummaryPeriodResponse.Unmarshal(m, b) @@ -1106,7 +1337,7 @@ func (m *SummarySatelliteRequest) Reset() { *m = SummarySatelliteRequest func (m *SummarySatelliteRequest) String() string { return proto.CompactTextString(m) } func (*SummarySatelliteRequest) ProtoMessage() {} func (*SummarySatelliteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{23} + return fileDescriptor_9a45fd79b06f3a1b, []int{28} } func (m *SummarySatelliteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SummarySatelliteRequest.Unmarshal(m, b) @@ -1144,7 +1375,7 @@ func (m *SummarySatelliteResponse) Reset() { *m = SummarySatelliteRespon func (m *SummarySatelliteResponse) String() string { return proto.CompactTextString(m) } func (*SummarySatelliteResponse) ProtoMessage() {} func (*SummarySatelliteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{24} + return fileDescriptor_9a45fd79b06f3a1b, []int{29} } func (m *SummarySatelliteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SummarySatelliteResponse.Unmarshal(m, b) @@ -1184,7 +1415,7 @@ func (m *SummarySatellitePeriodRequest) Reset() { *m = SummarySatelliteP func (m *SummarySatellitePeriodRequest) String() string { return proto.CompactTextString(m) } func (*SummarySatellitePeriodRequest) ProtoMessage() {} func (*SummarySatellitePeriodRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{25} + return fileDescriptor_9a45fd79b06f3a1b, []int{30} } func (m *SummarySatellitePeriodRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SummarySatellitePeriodRequest.Unmarshal(m, b) @@ -1229,7 +1460,7 @@ func (m *SummarySatellitePeriodResponse) Reset() { *m = SummarySatellite func (m *SummarySatellitePeriodResponse) String() string { return proto.CompactTextString(m) } func (*SummarySatellitePeriodResponse) ProtoMessage() {} func (*SummarySatellitePeriodResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{26} + return fileDescriptor_9a45fd79b06f3a1b, []int{31} } func (m *SummarySatellitePeriodResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_SummarySatellitePeriodResponse.Unmarshal(m, b) @@ -1267,7 +1498,7 @@ func (m *EarnedRequest) Reset() { *m = EarnedRequest{} } func (m *EarnedRequest) String() string { return proto.CompactTextString(m) } func (*EarnedRequest) ProtoMessage() {} func (*EarnedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{27} + return fileDescriptor_9a45fd79b06f3a1b, []int{32} } func (m *EarnedRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EarnedRequest.Unmarshal(m, b) @@ -1305,7 +1536,7 @@ func (m *EarnedResponse) Reset() { *m = EarnedResponse{} } func (m *EarnedResponse) String() string { return proto.CompactTextString(m) } func (*EarnedResponse) ProtoMessage() {} func (*EarnedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{28} + return fileDescriptor_9a45fd79b06f3a1b, []int{33} } func (m *EarnedResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EarnedResponse.Unmarshal(m, b) @@ -1343,7 +1574,7 @@ func (m *EarnedSatelliteRequest) Reset() { *m = EarnedSatelliteRequest{} func (m *EarnedSatelliteRequest) String() string { return proto.CompactTextString(m) } func (*EarnedSatelliteRequest) ProtoMessage() {} func (*EarnedSatelliteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{29} + return fileDescriptor_9a45fd79b06f3a1b, []int{34} } func (m *EarnedSatelliteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EarnedSatelliteRequest.Unmarshal(m, b) @@ -1381,7 +1612,7 @@ func (m *EarnedSatelliteResponse) Reset() { *m = EarnedSatelliteResponse func (m *EarnedSatelliteResponse) String() string { return proto.CompactTextString(m) } func (*EarnedSatelliteResponse) ProtoMessage() {} func (*EarnedSatelliteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{30} + return fileDescriptor_9a45fd79b06f3a1b, []int{35} } func (m *EarnedSatelliteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EarnedSatelliteResponse.Unmarshal(m, b) @@ -1420,7 +1651,7 @@ func (m *EarnedSatellite) Reset() { *m = EarnedSatellite{} } func (m *EarnedSatellite) String() string { return proto.CompactTextString(m) } func (*EarnedSatellite) ProtoMessage() {} func (*EarnedSatellite) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{31} + return fileDescriptor_9a45fd79b06f3a1b, []int{36} } func (m *EarnedSatellite) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_EarnedSatellite.Unmarshal(m, b) @@ -1458,7 +1689,7 @@ func (m *UndistributedRequest) Reset() { *m = UndistributedRequest{} } func (m *UndistributedRequest) String() string { return proto.CompactTextString(m) } func (*UndistributedRequest) ProtoMessage() {} func (*UndistributedRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{32} + return fileDescriptor_9a45fd79b06f3a1b, []int{37} } func (m *UndistributedRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UndistributedRequest.Unmarshal(m, b) @@ -1496,7 +1727,7 @@ func (m *UndistributedResponse) Reset() { *m = UndistributedResponse{} } func (m *UndistributedResponse) String() string { return proto.CompactTextString(m) } func (*UndistributedResponse) ProtoMessage() {} func (*UndistributedResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{33} + return fileDescriptor_9a45fd79b06f3a1b, []int{38} } func (m *UndistributedResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_UndistributedResponse.Unmarshal(m, b) @@ -1535,7 +1766,7 @@ func (m *PaystubSatelliteRequest) Reset() { *m = PaystubSatelliteRequest func (m *PaystubSatelliteRequest) String() string { return proto.CompactTextString(m) } func (*PaystubSatelliteRequest) ProtoMessage() {} func (*PaystubSatelliteRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{34} + return fileDescriptor_9a45fd79b06f3a1b, []int{39} } func (m *PaystubSatelliteRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PaystubSatelliteRequest.Unmarshal(m, b) @@ -1573,7 +1804,7 @@ func (m *PaystubSatelliteResponse) Reset() { *m = PaystubSatelliteRespon func (m *PaystubSatelliteResponse) String() string { return proto.CompactTextString(m) } func (*PaystubSatelliteResponse) ProtoMessage() {} func (*PaystubSatelliteResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{35} + return fileDescriptor_9a45fd79b06f3a1b, []int{40} } func (m *PaystubSatelliteResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PaystubSatelliteResponse.Unmarshal(m, b) @@ -1611,7 +1842,7 @@ func (m *PaystubRequest) Reset() { *m = PaystubRequest{} } func (m *PaystubRequest) String() string { return proto.CompactTextString(m) } func (*PaystubRequest) ProtoMessage() {} func (*PaystubRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{36} + return fileDescriptor_9a45fd79b06f3a1b, []int{41} } func (m *PaystubRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PaystubRequest.Unmarshal(m, b) @@ -1649,7 +1880,7 @@ func (m *PaystubResponse) Reset() { *m = PaystubResponse{} } func (m *PaystubResponse) String() string { return proto.CompactTextString(m) } func (*PaystubResponse) ProtoMessage() {} func (*PaystubResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{37} + return fileDescriptor_9a45fd79b06f3a1b, []int{42} } func (m *PaystubResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PaystubResponse.Unmarshal(m, b) @@ -1688,7 +1919,7 @@ func (m *PaystubPeriodRequest) Reset() { *m = PaystubPeriodRequest{} } func (m *PaystubPeriodRequest) String() string { return proto.CompactTextString(m) } func (*PaystubPeriodRequest) ProtoMessage() {} func (*PaystubPeriodRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{38} + return fileDescriptor_9a45fd79b06f3a1b, []int{43} } func (m *PaystubPeriodRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PaystubPeriodRequest.Unmarshal(m, b) @@ -1733,7 +1964,7 @@ func (m *PaystubPeriodResponse) Reset() { *m = PaystubPeriodResponse{} } func (m *PaystubPeriodResponse) String() string { return proto.CompactTextString(m) } func (*PaystubPeriodResponse) ProtoMessage() {} func (*PaystubPeriodResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{39} + return fileDescriptor_9a45fd79b06f3a1b, []int{44} } func (m *PaystubPeriodResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PaystubPeriodResponse.Unmarshal(m, b) @@ -1773,7 +2004,7 @@ func (m *PaystubSatellitePeriodRequest) Reset() { *m = PaystubSatelliteP func (m *PaystubSatellitePeriodRequest) String() string { return proto.CompactTextString(m) } func (*PaystubSatellitePeriodRequest) ProtoMessage() {} func (*PaystubSatellitePeriodRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{40} + return fileDescriptor_9a45fd79b06f3a1b, []int{45} } func (m *PaystubSatellitePeriodRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PaystubSatellitePeriodRequest.Unmarshal(m, b) @@ -1818,7 +2049,7 @@ func (m *PaystubSatellitePeriodResponse) Reset() { *m = PaystubSatellite func (m *PaystubSatellitePeriodResponse) String() string { return proto.CompactTextString(m) } func (*PaystubSatellitePeriodResponse) ProtoMessage() {} func (*PaystubSatellitePeriodResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{41} + return fileDescriptor_9a45fd79b06f3a1b, []int{46} } func (m *PaystubSatellitePeriodResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PaystubSatellitePeriodResponse.Unmarshal(m, b) @@ -1857,7 +2088,7 @@ func (m *PayoutInfo) Reset() { *m = PayoutInfo{} } func (m *PayoutInfo) String() string { return proto.CompactTextString(m) } func (*PayoutInfo) ProtoMessage() {} func (*PayoutInfo) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{42} + return fileDescriptor_9a45fd79b06f3a1b, []int{47} } func (m *PayoutInfo) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_PayoutInfo.Unmarshal(m, b) @@ -1913,7 +2144,7 @@ func (m *Paystub) Reset() { *m = Paystub{} } func (m *Paystub) String() string { return proto.CompactTextString(m) } func (*Paystub) ProtoMessage() {} func (*Paystub) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{43} + return fileDescriptor_9a45fd79b06f3a1b, []int{48} } func (m *Paystub) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_Paystub.Unmarshal(m, b) @@ -2028,7 +2259,7 @@ func (m *HeldAmountHistoryRequest) Reset() { *m = HeldAmountHistoryReque func (m *HeldAmountHistoryRequest) String() string { return proto.CompactTextString(m) } func (*HeldAmountHistoryRequest) ProtoMessage() {} func (*HeldAmountHistoryRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{44} + return fileDescriptor_9a45fd79b06f3a1b, []int{49} } func (m *HeldAmountHistoryRequest) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_HeldAmountHistoryRequest.Unmarshal(m, b) @@ -2066,7 +2297,7 @@ func (m *HeldAmountHistoryResponse) Reset() { *m = HeldAmountHistoryResp func (m *HeldAmountHistoryResponse) String() string { return proto.CompactTextString(m) } func (*HeldAmountHistoryResponse) ProtoMessage() {} func (*HeldAmountHistoryResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{45} + return fileDescriptor_9a45fd79b06f3a1b, []int{50} } func (m *HeldAmountHistoryResponse) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_HeldAmountHistoryResponse.Unmarshal(m, b) @@ -2105,7 +2336,7 @@ func (m *HeldAmountHistoryResponse_HeldAmount) Reset() { *m = HeldAmount func (m *HeldAmountHistoryResponse_HeldAmount) String() string { return proto.CompactTextString(m) } func (*HeldAmountHistoryResponse_HeldAmount) ProtoMessage() {} func (*HeldAmountHistoryResponse_HeldAmount) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{45, 0} + return fileDescriptor_9a45fd79b06f3a1b, []int{50, 0} } func (m *HeldAmountHistoryResponse_HeldAmount) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_HeldAmountHistoryResponse_HeldAmount.Unmarshal(m, b) @@ -2155,7 +2386,7 @@ func (m *HeldAmountHistoryResponse_HeldAmountHistory) String() string { } func (*HeldAmountHistoryResponse_HeldAmountHistory) ProtoMessage() {} func (*HeldAmountHistoryResponse_HeldAmountHistory) Descriptor() ([]byte, []int) { - return fileDescriptor_9a45fd79b06f3a1b, []int{45, 1} + return fileDescriptor_9a45fd79b06f3a1b, []int{50, 1} } func (m *HeldAmountHistoryResponse_HeldAmountHistory) XXX_Unmarshal(b []byte) error { return xxx_messageInfo_HeldAmountHistoryResponse_HeldAmountHistory.Unmarshal(m, b) @@ -2186,6 +2417,11 @@ func init() { proto.RegisterType((*RequestHeader)(nil), "multinode.RequestHeader") proto.RegisterType((*DiskSpaceRequest)(nil), "multinode.DiskSpaceRequest") proto.RegisterType((*DiskSpaceResponse)(nil), "multinode.DiskSpaceResponse") + proto.RegisterType((*StorageUsage)(nil), "multinode.StorageUsage") + proto.RegisterType((*StorageUsageRequest)(nil), "multinode.StorageUsageRequest") + proto.RegisterType((*StorageUsageResponse)(nil), "multinode.StorageUsageResponse") + proto.RegisterType((*StorageUsageSatelliteRequest)(nil), "multinode.StorageUsageSatelliteRequest") + proto.RegisterType((*StorageUsageSatelliteResponse)(nil), "multinode.StorageUsageSatelliteResponse") proto.RegisterType((*BandwidthMonthSummaryRequest)(nil), "multinode.BandwidthMonthSummaryRequest") proto.RegisterType((*BandwidthMonthSummaryResponse)(nil), "multinode.BandwidthMonthSummaryResponse") proto.RegisterType((*VersionRequest)(nil), "multinode.VersionRequest") @@ -2239,112 +2475,122 @@ func init() { func init() { proto.RegisterFile("multinode.proto", fileDescriptor_9a45fd79b06f3a1b) } var fileDescriptor_9a45fd79b06f3a1b = []byte{ - // 1698 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x58, 0x5f, 0x73, 0xd3, 0x48, - 0x12, 0x3f, 0xe3, 0xc4, 0x8e, 0xdb, 0x4e, 0x9c, 0xcc, 0xe5, 0x8f, 0x22, 0xf2, 0xef, 0x94, 0x14, - 0x84, 0x03, 0x9c, 0xbb, 0x70, 0x45, 0xd5, 0x55, 0x71, 0x75, 0x24, 0x10, 0x48, 0xee, 0x72, 0x10, - 0x14, 0xb8, 0xa2, 0xa0, 0x0a, 0x33, 0x89, 0x26, 0x8e, 0x16, 0x59, 0xd2, 0x6a, 0x46, 0x61, 0xf3, - 0xc2, 0x23, 0x6f, 0x5b, 0xb5, 0xcf, 0x5b, 0xfb, 0x5d, 0xf6, 0x6d, 0x8b, 0xcf, 0xb0, 0x0f, 0xec, - 0xf3, 0x7e, 0x82, 0x7d, 0xdd, 0x9a, 0x3f, 0x92, 0x25, 0x59, 0x36, 0x60, 0xd7, 0x2e, 0xfb, 0x36, - 0xd3, 0xdd, 0xf3, 0xeb, 0x9e, 0x9e, 0x9e, 0x99, 0xee, 0x86, 0x7a, 0x3b, 0x74, 0x98, 0xed, 0x7a, - 0x16, 0x69, 0xf8, 0x81, 0xc7, 0x3c, 0x54, 0x89, 0x09, 0x3a, 0xb4, 0xbc, 0x96, 0x27, 0xc9, 0xfa, - 0x72, 0xcb, 0xf3, 0x5a, 0x0e, 0xd9, 0x10, 0xb3, 0xa3, 0xf0, 0x64, 0x83, 0xd9, 0x6d, 0x42, 0x19, - 0x6e, 0xfb, 0x52, 0xc0, 0x58, 0x87, 0x71, 0x93, 0x7c, 0x19, 0x12, 0xca, 0x76, 0x09, 0xb6, 0x48, - 0x80, 0xe6, 0xa0, 0x8c, 0x7d, 0xbb, 0xf9, 0x8a, 0x9c, 0x6b, 0x85, 0x95, 0xc2, 0x7a, 0xcd, 0x2c, - 0x61, 0xdf, 0xfe, 0x2f, 0x39, 0x37, 0xee, 0xc2, 0xe4, 0x5d, 0x9b, 0xbe, 0x3a, 0xf4, 0xf1, 0x31, - 0x51, 0x4b, 0xd0, 0xdf, 0xa0, 0x74, 0x2a, 0x96, 0x09, 0xd9, 0xea, 0xa6, 0xd6, 0xe8, 0xd8, 0x95, - 0x82, 0x35, 0x95, 0x9c, 0xf1, 0x7d, 0x01, 0xa6, 0x12, 0x30, 0xd4, 0xf7, 0x5c, 0x4a, 0xd0, 0x02, - 0x54, 0xb0, 0xe3, 0x78, 0xc7, 0x98, 0x11, 0x4b, 0x40, 0x15, 0xcd, 0x0e, 0x01, 0x2d, 0x43, 0x35, - 0xa4, 0xc4, 0x6a, 0xfa, 0x36, 0x39, 0x26, 0x54, 0xbb, 0x20, 0xf8, 0xc0, 0x49, 0x07, 0x82, 0x82, - 0x16, 0x41, 0xcc, 0x9a, 0x2c, 0xc0, 0xf4, 0x54, 0x2b, 0xca, 0xf5, 0x9c, 0xf2, 0x98, 0x13, 0x10, - 0x82, 0x91, 0x93, 0x80, 0x10, 0x6d, 0x44, 0x30, 0xc4, 0x58, 0x68, 0x3c, 0xc3, 0xb6, 0x83, 0x8f, - 0x1c, 0xa2, 0x8d, 0x2a, 0x8d, 0x11, 0x01, 0xe9, 0x30, 0xe6, 0x9d, 0x91, 0x80, 0x43, 0x68, 0x25, - 0xc1, 0x8c, 0xe7, 0xc6, 0x01, 0x2c, 0x6c, 0x63, 0xd7, 0x7a, 0x6d, 0x5b, 0xec, 0xf4, 0x7f, 0x9e, - 0xcb, 0x4e, 0x0f, 0xc3, 0x76, 0x1b, 0x07, 0xe7, 0x83, 0xfb, 0xe4, 0x06, 0x2c, 0xf6, 0x40, 0x54, - 0xee, 0x41, 0x30, 0x22, 0x4c, 0x91, 0x9e, 0x11, 0x63, 0x63, 0x1b, 0x26, 0xfe, 0x4f, 0x02, 0x6a, - 0x7b, 0xee, 0xe0, 0x8a, 0xaf, 0x42, 0x3d, 0xc6, 0x50, 0xaa, 0x34, 0x28, 0x9f, 0x49, 0x92, 0x40, - 0xa9, 0x98, 0xd1, 0xd4, 0xb8, 0x07, 0x68, 0x1f, 0x53, 0x76, 0xc7, 0x73, 0x19, 0x3e, 0x66, 0x83, - 0x2b, 0x7d, 0x01, 0x7f, 0x4e, 0xe1, 0x28, 0xc5, 0xf7, 0xa1, 0xe6, 0x60, 0xca, 0x9a, 0xc7, 0x92, - 0xae, 0xe0, 0xf4, 0x86, 0x0c, 0xe0, 0x46, 0x14, 0xc0, 0x8d, 0xc7, 0x51, 0x00, 0x6f, 0x8f, 0xbd, - 0x7b, 0xbf, 0xfc, 0xa7, 0x6f, 0x7e, 0x5a, 0x2e, 0x98, 0x55, 0xa7, 0x03, 0x68, 0x7c, 0x05, 0x53, - 0x26, 0xf1, 0x43, 0x86, 0xd9, 0x30, 0xbe, 0x41, 0x7f, 0x87, 0x1a, 0xc5, 0x8c, 0x38, 0x8e, 0xcd, - 0x48, 0xd3, 0xb6, 0x44, 0xd4, 0xd5, 0xb6, 0x27, 0xb8, 0xce, 0x1f, 0xdf, 0x2f, 0x97, 0x1e, 0x78, - 0x16, 0xd9, 0xbb, 0x6b, 0x56, 0x63, 0x99, 0x3d, 0xcb, 0xf8, 0xa5, 0x00, 0x28, 0xa9, 0x5a, 0xed, - 0xec, 0x16, 0x94, 0x3c, 0xd7, 0xb1, 0x5d, 0xa2, 0x74, 0xaf, 0xa5, 0x74, 0x67, 0xc5, 0x1b, 0x0f, - 0x85, 0xac, 0xa9, 0xd6, 0xa0, 0x7f, 0xc2, 0x28, 0x0e, 0x2d, 0x9b, 0x09, 0x03, 0xaa, 0x9b, 0xab, - 0xfd, 0x17, 0x6f, 0x71, 0x51, 0x53, 0xae, 0xd0, 0x97, 0xa0, 0x24, 0xc1, 0xd0, 0x34, 0x8c, 0xd2, - 0x63, 0x2f, 0x90, 0x16, 0x14, 0x4c, 0x39, 0xd1, 0x77, 0x61, 0x54, 0xc8, 0xe7, 0xb3, 0xd1, 0x15, - 0x98, 0xa4, 0x21, 0xf5, 0x89, 0xcb, 0x8f, 0xbf, 0x29, 0x05, 0x2e, 0x08, 0x81, 0x7a, 0x87, 0x7e, - 0xc8, 0xc9, 0xc6, 0x3e, 0x68, 0x8f, 0x83, 0x90, 0x32, 0x62, 0x1d, 0x46, 0xfe, 0xa0, 0x83, 0x47, - 0xc8, 0x0f, 0x05, 0x98, 0xcf, 0x81, 0x53, 0xee, 0x7c, 0x0e, 0x88, 0x49, 0x66, 0x33, 0x76, 0x3e, - 0xd5, 0x0a, 0x2b, 0xc5, 0xf5, 0xea, 0xe6, 0xb5, 0x04, 0x76, 0x4f, 0x84, 0x06, 0x3f, 0xbb, 0x27, - 0xe6, 0xbe, 0x39, 0xc5, 0xb2, 0x22, 0xfa, 0x3e, 0x94, 0x15, 0x17, 0x5d, 0x86, 0x32, 0xc7, 0xe1, - 0x67, 0x5f, 0xc8, 0x3d, 0xfb, 0x12, 0x67, 0xef, 0x59, 0xfc, 0xca, 0x60, 0xcb, 0x0a, 0x08, 0x95, - 0x4f, 0x53, 0xc5, 0x8c, 0xa6, 0xc6, 0x1d, 0xa8, 0x3f, 0xf4, 0x49, 0x80, 0x99, 0x17, 0x0c, 0xee, - 0x0d, 0x1b, 0x26, 0x3b, 0x20, 0xca, 0x07, 0xd3, 0x30, 0x4a, 0xda, 0xd8, 0x76, 0xd4, 0x1d, 0x95, - 0x13, 0x34, 0x0b, 0xa5, 0xd7, 0xd8, 0x71, 0x08, 0x53, 0x76, 0xa8, 0x19, 0xba, 0x0c, 0x75, 0x39, - 0x6a, 0x9e, 0x10, 0xcc, 0xc2, 0x80, 0x50, 0xad, 0xb8, 0x52, 0x5c, 0xaf, 0x98, 0x13, 0x92, 0x7c, - 0x4f, 0x51, 0x8d, 0xb7, 0x05, 0x58, 0xde, 0xa1, 0xcc, 0x6e, 0xf3, 0x67, 0xf7, 0x00, 0x9f, 0x7b, - 0x21, 0x8b, 0x7d, 0xf3, 0xbb, 0xde, 0xa4, 0x47, 0xb0, 0xd2, 0xdb, 0x0e, 0xe5, 0x83, 0xeb, 0x80, - 0x48, 0x24, 0xd3, 0x24, 0x38, 0x70, 0x6d, 0xb7, 0x45, 0xd5, 0x13, 0x39, 0x15, 0x73, 0x76, 0x14, - 0xc3, 0xf8, 0x0f, 0xcc, 0x66, 0x20, 0x07, 0x3f, 0x92, 0x5d, 0x98, 0xeb, 0xc2, 0x1a, 0xcc, 0xaa, - 0x6d, 0x98, 0x18, 0xfa, 0xfb, 0xd8, 0x83, 0x7a, 0xf6, 0xc3, 0xb8, 0x09, 0x55, 0x5f, 0xd8, 0xd5, - 0xb4, 0xdd, 0x13, 0x4f, 0x21, 0xcd, 0x24, 0x90, 0xa4, 0xd5, 0x7b, 0xee, 0x89, 0x67, 0x82, 0x1f, - 0x8f, 0x8d, 0x97, 0x30, 0xad, 0xa0, 0x0e, 0x48, 0x60, 0x7b, 0xd6, 0xe0, 0x87, 0x3e, 0x0b, 0x25, - 0x5f, 0x40, 0x44, 0xb1, 0x28, 0x67, 0xc6, 0x43, 0x98, 0xc9, 0x68, 0x18, 0xd2, 0xe4, 0x37, 0x30, - 0xa7, 0x00, 0x3f, 0x4f, 0xa8, 0x9a, 0xa0, 0x75, 0xeb, 0x1f, 0x72, 0x4f, 0xdf, 0x15, 0x60, 0x31, - 0x0b, 0x3a, 0xec, 0x81, 0x7c, 0xfa, 0xd6, 0x12, 0x67, 0x58, 0x4c, 0x9d, 0xe1, 0x53, 0x58, 0xea, - 0x65, 0xdd, 0x90, 0x1b, 0xdf, 0x82, 0x71, 0x7e, 0x35, 0xc8, 0xe0, 0xfb, 0x34, 0x2e, 0xc1, 0x44, - 0x04, 0xd1, 0x79, 0x2c, 0x99, 0xc7, 0xb0, 0xa3, 0x6e, 0xa1, 0x9c, 0x88, 0xf7, 0x40, 0xc8, 0x0d, - 0x1f, 0x36, 0xc6, 0x4b, 0x98, 0xeb, 0xc2, 0x52, 0xca, 0x77, 0x60, 0x92, 0x08, 0x56, 0xe7, 0xb3, - 0x52, 0x7f, 0x95, 0x9e, 0x80, 0xcd, 0xae, 0xae, 0x93, 0x34, 0xc1, 0x78, 0x06, 0xf5, 0x8c, 0x4c, - 0xfe, 0xb6, 0x06, 0x89, 0xe0, 0x5d, 0x98, 0x7e, 0xe2, 0x5a, 0x36, 0x65, 0x81, 0x7d, 0x14, 0xb2, - 0x61, 0x7c, 0x7f, 0x1d, 0x66, 0x32, 0x48, 0x7d, 0x8f, 0xe0, 0x0d, 0xcc, 0x1d, 0xe0, 0x73, 0xca, - 0xc2, 0xa3, 0xcf, 0x73, 0x75, 0x77, 0x41, 0xeb, 0xd6, 0xaf, 0x2c, 0xbe, 0x06, 0x65, 0x5f, 0xf2, - 0x94, 0x05, 0x28, 0x1d, 0xbd, 0x9c, 0x63, 0x46, 0x22, 0xfc, 0x19, 0x8f, 0x68, 0x03, 0x3b, 0xef, - 0xdf, 0x50, 0x8f, 0x31, 0x06, 0x32, 0xe2, 0x25, 0x4c, 0x2b, 0xda, 0x6f, 0xf5, 0x78, 0xef, 0xc0, - 0x4c, 0x46, 0xc3, 0x40, 0x86, 0xf2, 0xe7, 0x2d, 0xeb, 0xf8, 0x3f, 0xd0, 0xf3, 0xf6, 0x00, 0x96, - 0x7a, 0x59, 0x37, 0xd0, 0x76, 0xff, 0x01, 0xd0, 0x79, 0xee, 0x78, 0x2d, 0x77, 0x4a, 0x9c, 0xb8, - 0x96, 0xe3, 0x63, 0x4e, 0xf3, 0xb1, 0x32, 0xba, 0x68, 0x8a, 0xb1, 0xf1, 0x75, 0x11, 0xca, 0x0a, - 0x0a, 0x19, 0x30, 0x1e, 0x52, 0xdc, 0x22, 0x4d, 0xcc, 0x9a, 0x01, 0xa1, 0x4c, 0xe5, 0xe9, 0x55, - 0x41, 0xdc, 0xe2, 0xc9, 0x07, 0x43, 0x17, 0xa1, 0x22, 0x65, 0x5a, 0x2a, 0xff, 0x2b, 0x9a, 0x63, - 0x82, 0x70, 0x9f, 0x30, 0xb4, 0x0e, 0x93, 0x31, 0xb3, 0x19, 0x10, 0x1f, 0xdb, 0x81, 0x2a, 0x93, - 0x27, 0x22, 0x19, 0x53, 0x50, 0xd1, 0x25, 0xa8, 0x77, 0x24, 0x65, 0xe1, 0x21, 0xcb, 0xe6, 0xf1, - 0x48, 0x50, 0x96, 0x0c, 0x2b, 0x50, 0x3b, 0xf6, 0xda, 0x7e, 0x6c, 0x91, 0x2c, 0xa1, 0x81, 0xd3, - 0x94, 0x41, 0xf3, 0x30, 0x26, 0x24, 0xb8, 0x3d, 0xb2, 0x86, 0x2e, 0xf3, 0x39, 0x37, 0xe7, 0x12, - 0xd4, 0x23, 0x56, 0x64, 0x4d, 0x59, 0x2a, 0x51, 0x12, 0xca, 0x98, 0x35, 0x98, 0x88, 0xe5, 0xa4, - 0x2d, 0x63, 0x42, 0xac, 0xa6, 0xc4, 0xa4, 0x29, 0x91, 0x47, 0x2b, 0x39, 0x1e, 0x85, 0x8e, 0x47, - 0xd1, 0x0a, 0x54, 0x13, 0x6f, 0x93, 0x56, 0x15, 0xac, 0x24, 0x89, 0x97, 0xfd, 0x96, 0x4d, 0x7d, - 0x8f, 0xd7, 0xda, 0x35, 0xe9, 0xc2, 0x68, 0xce, 0x4b, 0x9c, 0x5d, 0xe2, 0x58, 0x5b, 0x6d, 0x2f, - 0x74, 0xd9, 0xae, 0x4d, 0x99, 0x37, 0x4c, 0xce, 0xf6, 0xee, 0x02, 0xcc, 0xe7, 0xc0, 0xa9, 0xf8, - 0x3a, 0x80, 0xf2, 0xa9, 0x24, 0xa9, 0xbf, 0xe2, 0x66, 0x02, 0xb0, 0xe7, 0xb2, 0x1c, 0x4e, 0x04, - 0xa3, 0xdf, 0x02, 0xe8, 0x70, 0x13, 0x91, 0x5f, 0x48, 0x46, 0x3e, 0xa7, 0x63, 0x21, 0xa1, 0x02, - 0x48, 0xcd, 0xf4, 0x6f, 0x0b, 0x30, 0xd5, 0x05, 0xde, 0x75, 0xe5, 0x0a, 0x1f, 0xbe, 0x72, 0x26, - 0xd4, 0xf8, 0xf1, 0x34, 0x25, 0x2e, 0xaf, 0x97, 0xf8, 0xee, 0x36, 0x3e, 0x71, 0x77, 0x66, 0xf5, - 0x34, 0x1e, 0xd3, 0xcd, 0x47, 0x50, 0x3e, 0x64, 0x5e, 0x80, 0x5b, 0x04, 0xdd, 0x83, 0x4a, 0xdc, - 0x5b, 0x42, 0x17, 0x13, 0xa8, 0xd9, 0xc6, 0x95, 0xbe, 0x90, 0xcf, 0x94, 0xaa, 0x36, 0x5d, 0xa8, - 0xc4, 0x0d, 0x19, 0x84, 0xa1, 0x96, 0x6c, 0xca, 0xa0, 0xcb, 0x89, 0xa5, 0xfd, 0x1a, 0x41, 0xfa, - 0xfa, 0x87, 0x05, 0x95, 0xbe, 0xb7, 0x45, 0x18, 0xe1, 0xee, 0x42, 0xb7, 0xa1, 0xac, 0x1a, 0x32, - 0x68, 0x3e, 0xb1, 0x3a, 0xdd, 0xe8, 0xd1, 0xf5, 0x3c, 0x96, 0x0a, 0x9d, 0x7d, 0xa8, 0x26, 0xba, - 0x2b, 0x68, 0x31, 0x21, 0xda, 0xdd, 0xbd, 0xd1, 0x97, 0x7a, 0xb1, 0x15, 0xda, 0x1e, 0x40, 0xa7, - 0xc9, 0x80, 0x16, 0x7a, 0xf4, 0x1e, 0x24, 0xd6, 0x62, 0xdf, 0xce, 0x04, 0x7a, 0x01, 0x53, 0x5d, - 0x15, 0x39, 0x5a, 0xed, 0x5f, 0xaf, 0x4b, 0xe0, 0xb5, 0x8f, 0x29, 0xea, 0xd1, 0x1d, 0x18, 0x8b, - 0xca, 0x64, 0x94, 0x74, 0x50, 0xa6, 0x00, 0xd7, 0x2f, 0xe6, 0xf2, 0xd4, 0x41, 0xfc, 0x5c, 0x11, - 0x8f, 0xae, 0x17, 0x32, 0xca, 0xcf, 0x22, 0x3a, 0xf2, 0xe4, 0x59, 0x64, 0x0e, 0x59, 0xcf, 0x63, - 0x29, 0x93, 0x4c, 0x18, 0x4f, 0xd5, 0x3a, 0x68, 0xb9, 0x5b, 0x38, 0xf5, 0xef, 0xe9, 0x2b, 0xbd, - 0x05, 0xe2, 0xee, 0xc7, 0x64, 0x36, 0xf7, 0x46, 0x46, 0xf7, 0xaa, 0x6c, 0x42, 0xa5, 0xaf, 0xf6, - 0x95, 0x51, 0xe0, 0x6d, 0x98, 0xcd, 0x4f, 0xec, 0xd1, 0x7a, 0x9f, 0xe5, 0xe9, 0x2d, 0x5c, 0xf9, - 0x08, 0x49, 0xa5, 0xee, 0x5f, 0x50, 0x92, 0x49, 0x2d, 0xd2, 0xba, 0x72, 0xe1, 0x08, 0x6e, 0x3e, - 0x87, 0xa3, 0x96, 0x3f, 0xed, 0xce, 0x89, 0xff, 0xd2, 0x27, 0xa7, 0x56, 0x80, 0x46, 0x3f, 0x11, - 0x85, 0x4c, 0x41, 0xeb, 0xd5, 0x7e, 0x40, 0x7f, 0x4d, 0xae, 0xef, 0xdf, 0x2b, 0xd1, 0xaf, 0x7e, - 0x94, 0x6c, 0x62, 0x3b, 0x69, 0x99, 0xf4, 0x76, 0x72, 0x9b, 0x17, 0xe9, 0xed, 0xf4, 0xe8, 0x49, - 0x98, 0x30, 0x9e, 0x4a, 0xcb, 0x53, 0x71, 0x98, 0x97, 0xfa, 0xa7, 0xe2, 0x30, 0x3f, 0xa3, 0x7f, - 0x0e, 0x93, 0xd9, 0x24, 0x29, 0x15, 0x87, 0x3d, 0x12, 0xfb, 0x54, 0x1c, 0xf6, 0x4c, 0xbe, 0x6f, - 0x77, 0x52, 0x9f, 0xf9, 0x9c, 0xcc, 0x2a, 0xe7, 0xea, 0x65, 0x33, 0x67, 0x13, 0xc6, 0x53, 0x99, - 0x6a, 0x6a, 0xcb, 0x79, 0x59, 0x72, 0x6a, 0xcb, 0xf9, 0x49, 0x6e, 0x1b, 0x66, 0xf3, 0xf3, 0xc2, - 0xd4, 0xed, 0xe8, 0x9b, 0xd8, 0xa6, 0x6e, 0xc7, 0x07, 0x92, 0xcc, 0x17, 0x79, 0x7f, 0xee, 0x6a, - 0xff, 0xaf, 0xb2, 0xfb, 0xc1, 0xec, 0xf9, 0x9f, 0x6e, 0xaf, 0x3d, 0x33, 0x38, 0xe1, 0x8b, 0x86, - 0xed, 0x6d, 0x88, 0xc1, 0x86, 0x1f, 0xd8, 0x67, 0x98, 0x91, 0x8d, 0x78, 0xb5, 0x7f, 0x74, 0x54, - 0x12, 0x8d, 0xf7, 0x1b, 0xbf, 0x06, 0x00, 0x00, 0xff, 0xff, 0xa3, 0xcb, 0x70, 0x14, 0x71, 0x1a, - 0x00, 0x00, + // 1868 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x59, 0xcd, 0x73, 0xe4, 0x46, + 0x15, 0x67, 0x3c, 0xf6, 0x8c, 0xe7, 0xcd, 0x97, 0xdd, 0xf1, 0xda, 0x63, 0xad, 0xbf, 0xd0, 0x6e, + 0xed, 0x3a, 0x24, 0xb1, 0xc1, 0x49, 0xa5, 0xa0, 0x2a, 0x14, 0x59, 0xef, 0x47, 0x6c, 0x62, 0xb2, + 0x46, 0xf6, 0x52, 0xa9, 0xa4, 0x58, 0x6d, 0xdb, 0x6a, 0x8f, 0x45, 0x34, 0x6a, 0xa1, 0xee, 0x71, + 0xf0, 0x25, 0x70, 0xca, 0x8d, 0x2a, 0xce, 0x14, 0xff, 0x07, 0x47, 0x6e, 0x54, 0xfe, 0x06, 0x0e, + 0xe1, 0xcc, 0x99, 0x03, 0x57, 0xaa, 0x3f, 0xa4, 0x91, 0x34, 0xd2, 0xac, 0x57, 0x03, 0xb5, 0xb9, + 0xa9, 0xdf, 0xc7, 0xef, 0xbd, 0x7e, 0xaf, 0xbf, 0xde, 0x13, 0x74, 0x07, 0x43, 0x8f, 0xbb, 0x3e, + 0x75, 0xc8, 0x4e, 0x10, 0x52, 0x4e, 0x51, 0x23, 0x26, 0x18, 0xd0, 0xa7, 0x7d, 0xaa, 0xc8, 0xc6, + 0x66, 0x9f, 0xd2, 0xbe, 0x47, 0x76, 0xe5, 0xe8, 0x6c, 0x78, 0xb1, 0xcb, 0xdd, 0x01, 0x61, 0x1c, + 0x0f, 0x02, 0x25, 0x60, 0x6e, 0x43, 0xdb, 0x22, 0xbf, 0x1d, 0x12, 0xc6, 0x0f, 0x08, 0x76, 0x48, + 0x88, 0x56, 0xa0, 0x8e, 0x03, 0xd7, 0xfe, 0x82, 0x5c, 0xf7, 0x2a, 0x5b, 0x95, 0xed, 0x96, 0x55, + 0xc3, 0x81, 0xfb, 0x31, 0xb9, 0x36, 0x1f, 0xc1, 0xc2, 0x23, 0x97, 0x7d, 0x71, 0x12, 0xe0, 0x73, + 0xa2, 0x55, 0xd0, 0x0f, 0xa1, 0x76, 0x29, 0xd5, 0xa4, 0x6c, 0x73, 0xaf, 0xb7, 0x33, 0xf2, 0x2b, + 0x05, 0x6b, 0x69, 0x39, 0xf3, 0x6f, 0x15, 0x58, 0x4c, 0xc0, 0xb0, 0x80, 0xfa, 0x8c, 0xa0, 0x35, + 0x68, 0x60, 0xcf, 0xa3, 0xe7, 0x98, 0x13, 0x47, 0x42, 0x55, 0xad, 0x11, 0x01, 0x6d, 0x42, 0x73, + 0xc8, 0x88, 0x63, 0x07, 0x2e, 0x39, 0x27, 0xac, 0x37, 0x23, 0xf9, 0x20, 0x48, 0xc7, 0x92, 0x82, + 0xd6, 0x41, 0x8e, 0x6c, 0x1e, 0x62, 0x76, 0xd9, 0xab, 0x2a, 0x7d, 0x41, 0x39, 0x15, 0x04, 0x84, + 0x60, 0xf6, 0x22, 0x24, 0xa4, 0x37, 0x2b, 0x19, 0xf2, 0x5b, 0x5a, 0xbc, 0xc2, 0xae, 0x87, 0xcf, + 0x3c, 0xd2, 0x9b, 0xd3, 0x16, 0x23, 0x02, 0x32, 0x60, 0x9e, 0x5e, 0x91, 0x50, 0x40, 0xf4, 0x6a, + 0x92, 0x19, 0x8f, 0xcd, 0xdf, 0x43, 0xeb, 0x84, 0xd3, 0x10, 0xf7, 0xc9, 0x33, 0x86, 0xfb, 0x04, + 0x99, 0xd0, 0xc6, 0xdc, 0x0e, 0x09, 0xe3, 0x36, 0xa7, 0x1c, 0x7b, 0xd2, 0xff, 0x8a, 0xd5, 0xc4, + 0xdc, 0x22, 0x8c, 0x9f, 0x0a, 0x12, 0xfa, 0x18, 0x3a, 0xae, 0xcf, 0x49, 0x78, 0x85, 0x3d, 0x9b, + 0x71, 0x1c, 0x72, 0x39, 0x89, 0xe6, 0x9e, 0xb1, 0xa3, 0xf2, 0xb3, 0x13, 0xe5, 0x67, 0xe7, 0x34, + 0xca, 0xcf, 0xfe, 0xfc, 0x37, 0xdf, 0x6e, 0x7e, 0xef, 0x4f, 0xff, 0xdc, 0xac, 0x58, 0xed, 0x48, + 0xf7, 0x44, 0xa8, 0x9a, 0x7f, 0xad, 0xc0, 0x1b, 0x49, 0x0f, 0x4a, 0x27, 0x03, 0xfd, 0x58, 0x04, + 0x86, 0x0e, 0x5e, 0xc9, 0x19, 0xa9, 0x81, 0xde, 0x83, 0x19, 0x4e, 0x65, 0xa4, 0x6f, 0xaa, 0x37, + 0xc3, 0xa9, 0x79, 0x0a, 0x4b, 0x69, 0xc7, 0x75, 0xfa, 0x3f, 0x80, 0x36, 0x53, 0x74, 0x7b, 0x28, + 0x18, 0xbd, 0xca, 0x56, 0x75, 0xbb, 0xb9, 0xb7, 0x92, 0x98, 0x40, 0x4a, 0xaf, 0xc5, 0x12, 0x23, + 0xf3, 0xdf, 0x15, 0x58, 0x4b, 0xb2, 0x4f, 0x30, 0x27, 0x9e, 0xe7, 0xf2, 0x29, 0x02, 0xf3, 0x23, + 0x68, 0xb1, 0x08, 0xc5, 0x76, 0x1d, 0x19, 0xa0, 0xd6, 0x7e, 0x47, 0x4c, 0xe6, 0x1f, 0xdf, 0x6e, + 0xd6, 0x3e, 0xa1, 0x0e, 0x39, 0x7c, 0x64, 0x35, 0x63, 0x99, 0x43, 0x27, 0x8e, 0x65, 0xb5, 0x64, + 0x2c, 0x67, 0x5f, 0x31, 0x96, 0xbf, 0x86, 0xf5, 0x82, 0x49, 0xff, 0x4f, 0x82, 0x7a, 0x0c, 0x6b, + 0xfb, 0xd8, 0x77, 0xbe, 0x74, 0x1d, 0x7e, 0xf9, 0x0b, 0xea, 0xf3, 0xcb, 0x93, 0xe1, 0x60, 0x80, + 0xc3, 0xeb, 0xf2, 0x3b, 0xff, 0x5d, 0x58, 0x2f, 0x40, 0xd4, 0x0e, 0x23, 0x98, 0x95, 0x1b, 0x4e, + 0xed, 0x7f, 0xf9, 0x6d, 0xee, 0x43, 0xe7, 0x57, 0x24, 0x64, 0x2e, 0xf5, 0xcb, 0x1b, 0x7e, 0x0b, + 0xba, 0x31, 0x86, 0x36, 0xd5, 0x83, 0xfa, 0x95, 0x22, 0x49, 0x94, 0x86, 0x15, 0x0d, 0xcd, 0x27, + 0x80, 0x8e, 0x30, 0xe3, 0x0f, 0xa9, 0xcf, 0xf1, 0x39, 0x2f, 0x6f, 0xf4, 0x39, 0xbc, 0x91, 0xc2, + 0xd1, 0x86, 0x3f, 0x82, 0x96, 0x87, 0x19, 0xb7, 0xcf, 0x15, 0x5d, 0xc3, 0xdd, 0x2c, 0xeb, 0x4d, + 0x6f, 0x04, 0x68, 0xfe, 0x0e, 0x16, 0x2d, 0x12, 0x0c, 0x39, 0xe6, 0xd3, 0xc4, 0xa6, 0xc4, 0x42, + 0x37, 0xff, 0x53, 0x01, 0x94, 0x34, 0x1d, 0x2f, 0xb7, 0x1a, 0xf5, 0x3d, 0xd7, 0x27, 0xda, 0xf6, + 0xdd, 0x94, 0xed, 0xac, 0xf8, 0xce, 0x53, 0x29, 0x6b, 0x69, 0x1d, 0xf4, 0x13, 0x98, 0xc3, 0x43, + 0xc7, 0x8d, 0xce, 0xc5, 0x3b, 0x93, 0x95, 0x1f, 0x08, 0x51, 0x4b, 0x69, 0x18, 0x1b, 0x50, 0x53, + 0x60, 0x68, 0x09, 0xe6, 0xd8, 0x39, 0x0d, 0x89, 0x3e, 0x81, 0xd5, 0xc0, 0x38, 0x80, 0x39, 0x29, + 0x9f, 0xcf, 0x46, 0x6f, 0xc2, 0x02, 0x1b, 0xb2, 0x80, 0xf8, 0x22, 0xfd, 0xb6, 0x12, 0x98, 0x91, + 0x02, 0xdd, 0x11, 0xfd, 0x44, 0x90, 0xcd, 0x23, 0xe8, 0x9d, 0x86, 0x43, 0xc6, 0x89, 0x13, 0xef, + 0x36, 0x56, 0x7e, 0x85, 0xfc, 0xbd, 0x02, 0xab, 0x39, 0x70, 0x3a, 0x9c, 0x9f, 0x03, 0xe2, 0x8a, + 0x69, 0xc7, 0xc1, 0x67, 0x7a, 0x0b, 0xbf, 0x9d, 0xc0, 0x2e, 0x44, 0xd8, 0x11, 0xb9, 0x7b, 0x66, + 0x1d, 0x59, 0x8b, 0x3c, 0x2b, 0x62, 0x1c, 0x41, 0x5d, 0x73, 0xd1, 0x7d, 0xa8, 0x0b, 0x1c, 0x91, + 0xfb, 0x4a, 0x6e, 0xee, 0x6b, 0x82, 0x7d, 0xe8, 0x88, 0x2d, 0x83, 0x1d, 0x27, 0x24, 0x4c, 0x5d, + 0xc0, 0x0d, 0x2b, 0x1a, 0x9a, 0x0f, 0xa1, 0xfb, 0x34, 0x20, 0x21, 0xe6, 0x34, 0x2c, 0x1f, 0x0d, + 0x17, 0x16, 0x46, 0x20, 0x3a, 0x06, 0x4b, 0x30, 0x47, 0x06, 0xd8, 0xf5, 0xf4, 0x1e, 0x55, 0x03, + 0xb4, 0x0c, 0xb5, 0x2f, 0xb1, 0xe7, 0x11, 0xae, 0xfd, 0xd0, 0x23, 0x74, 0x1f, 0xba, 0xea, 0xcb, + 0xbe, 0x20, 0x98, 0x0f, 0x43, 0xc2, 0x7a, 0xd5, 0xad, 0xea, 0x76, 0xc3, 0xea, 0x28, 0xf2, 0x13, + 0x4d, 0x35, 0xbf, 0xae, 0xc0, 0xe6, 0x63, 0xc6, 0xdd, 0x81, 0x78, 0x5c, 0x1c, 0xe3, 0x6b, 0x3a, + 0xe4, 0xaf, 0xe5, 0xca, 0x30, 0x7f, 0x09, 0x5b, 0xc5, 0x7e, 0xe8, 0x18, 0xbc, 0x03, 0x88, 0x44, + 0x32, 0x36, 0xc1, 0xa1, 0xef, 0xfa, 0x7d, 0xa6, 0x8f, 0xc8, 0xc5, 0x98, 0xf3, 0x58, 0x33, 0xcc, + 0x9f, 0xc3, 0x72, 0x06, 0xb2, 0x7c, 0x4a, 0x0e, 0x60, 0x65, 0x0c, 0xab, 0x9c, 0x57, 0xfb, 0xd0, + 0x99, 0xfa, 0xfa, 0x38, 0x84, 0x6e, 0xf6, 0xc2, 0x78, 0x1f, 0x9a, 0x81, 0xf4, 0xcb, 0x76, 0xfd, + 0x0b, 0xaa, 0x91, 0x6e, 0x25, 0x90, 0x94, 0xd7, 0x87, 0xfe, 0x05, 0xb5, 0x20, 0x88, 0xbf, 0xcd, + 0x17, 0xb0, 0xa4, 0xa1, 0x8e, 0x49, 0xe8, 0x52, 0xa7, 0x7c, 0xd2, 0x97, 0xa1, 0x16, 0x48, 0x88, + 0x68, 0x2d, 0xaa, 0x91, 0xf9, 0x14, 0x6e, 0x65, 0x2c, 0x4c, 0xe9, 0xf2, 0x57, 0xb0, 0xa2, 0x01, + 0x5f, 0xcf, 0x52, 0xb5, 0xa0, 0x37, 0x6e, 0x7f, 0xca, 0x39, 0xfd, 0xa5, 0x02, 0xeb, 0x59, 0xd0, + 0x69, 0x13, 0x52, 0xe2, 0xe1, 0x36, 0xca, 0x61, 0x35, 0x95, 0xc3, 0x4f, 0x61, 0xa3, 0xc8, 0xbb, + 0x29, 0x27, 0xfe, 0x00, 0xda, 0x62, 0x6b, 0x90, 0xf2, 0xf3, 0x34, 0xef, 0x41, 0x27, 0x82, 0x18, + 0x1d, 0x96, 0xa3, 0xf2, 0xa3, 0x6a, 0xa9, 0x81, 0x3c, 0x0f, 0xa4, 0xdc, 0xf4, 0xcb, 0xc6, 0x7c, + 0x01, 0x2b, 0x63, 0x58, 0xda, 0xf8, 0x63, 0x58, 0x20, 0x92, 0x35, 0xba, 0xac, 0xf4, 0x5d, 0x65, + 0x24, 0x60, 0xb3, 0xda, 0x5d, 0x92, 0x26, 0x98, 0x9f, 0x41, 0x37, 0x23, 0x93, 0x3f, 0xad, 0x32, + 0x2b, 0xf8, 0x00, 0x96, 0x9e, 0xf9, 0x8e, 0xcb, 0x78, 0xe8, 0x9e, 0x0d, 0xf9, 0x34, 0xb1, 0x7f, + 0x07, 0x6e, 0x65, 0x90, 0x26, 0xa6, 0xe0, 0x2b, 0x58, 0x39, 0xc6, 0xd7, 0x8c, 0x0f, 0xcf, 0x5e, + 0xcf, 0xd6, 0x3d, 0x80, 0xde, 0xb8, 0x7d, 0xed, 0xf1, 0xdb, 0x50, 0x0f, 0x14, 0x4f, 0x7b, 0x80, + 0xd2, 0xab, 0x57, 0x70, 0xac, 0x48, 0x44, 0x1c, 0xe3, 0x11, 0xad, 0x74, 0xf0, 0x7e, 0x06, 0xdd, + 0x18, 0xa3, 0x94, 0x13, 0x2f, 0x60, 0x49, 0xd3, 0xfe, 0x5f, 0x87, 0xf7, 0x63, 0xb8, 0x95, 0xb1, + 0x50, 0xca, 0x51, 0x71, 0xbc, 0x65, 0x03, 0xff, 0x1d, 0x3a, 0xde, 0x3e, 0x81, 0x8d, 0x22, 0xef, + 0x4a, 0x4d, 0xf7, 0x3d, 0x80, 0xd1, 0x71, 0x27, 0x6a, 0xb9, 0x4b, 0xe2, 0xc5, 0xb5, 0x9c, 0xf8, + 0x16, 0xb4, 0x00, 0x6b, 0xa7, 0xab, 0x96, 0xfc, 0x36, 0xff, 0x58, 0x85, 0xba, 0x86, 0x42, 0x26, + 0xb4, 0x65, 0xa1, 0x6a, 0xeb, 0x76, 0x4a, 0xd4, 0x48, 0x91, 0xc4, 0x07, 0xb2, 0x9b, 0x82, 0x6e, + 0x43, 0x43, 0xc9, 0xf4, 0xf5, 0xfb, 0xaf, 0x6a, 0xcd, 0x4b, 0xc2, 0x47, 0x84, 0xa3, 0x6d, 0x58, + 0x88, 0x99, 0x76, 0x48, 0x02, 0xec, 0x86, 0xba, 0x19, 0xd4, 0x89, 0x64, 0x2c, 0x49, 0x45, 0xf7, + 0xa0, 0x3b, 0x92, 0x54, 0x85, 0x87, 0x6a, 0x0e, 0xb5, 0x23, 0x41, 0x55, 0x32, 0x6c, 0x41, 0xeb, + 0x9c, 0x0e, 0x82, 0xd8, 0x23, 0xd5, 0x28, 0x02, 0x41, 0xd3, 0x0e, 0xad, 0xc2, 0xbc, 0x94, 0x10, + 0xfe, 0xa8, 0x4e, 0x51, 0x5d, 0x8c, 0x85, 0x3b, 0xf7, 0xa0, 0x1b, 0xb1, 0x22, 0x6f, 0xea, 0xca, + 0x88, 0x96, 0xd0, 0xce, 0xdc, 0x85, 0x4e, 0x2c, 0xa7, 0x7c, 0x99, 0x97, 0x62, 0x2d, 0x2d, 0xa6, + 0x5c, 0x89, 0x22, 0xda, 0xc8, 0x89, 0x28, 0x8c, 0x22, 0x8a, 0xb6, 0xa0, 0x99, 0x38, 0x9b, 0x7a, + 0x4d, 0xc9, 0x4a, 0x92, 0x90, 0x01, 0xf3, 0x8e, 0xcb, 0x02, 0x2a, 0x6a, 0xed, 0x96, 0x0a, 0x61, + 0x34, 0x16, 0x25, 0xce, 0x01, 0xf1, 0x9c, 0x07, 0x03, 0x3a, 0xf4, 0xf9, 0x81, 0xcb, 0x38, 0x9d, + 0xe6, 0xcd, 0xf6, 0xcd, 0x0c, 0xac, 0xe6, 0xc0, 0xe9, 0xf5, 0x75, 0x0c, 0xf5, 0x4b, 0x45, 0xd2, + 0x77, 0xc5, 0xfb, 0x09, 0xc0, 0x42, 0xb5, 0x1c, 0x4e, 0x04, 0x63, 0x7c, 0x00, 0x30, 0xe2, 0x26, + 0x56, 0x7e, 0x25, 0xb9, 0xf2, 0x05, 0x1d, 0x4b, 0x09, 0xbd, 0x80, 0xf4, 0xc8, 0xf8, 0x73, 0x05, + 0x16, 0xc7, 0xc0, 0xc7, 0xb6, 0x5c, 0xe5, 0xe5, 0x5b, 0xce, 0x82, 0x96, 0x48, 0x8f, 0xad, 0x70, + 0x45, 0xbd, 0x24, 0x66, 0xb7, 0xfb, 0x8a, 0xb3, 0xb3, 0x9a, 0x97, 0xf1, 0x37, 0xdb, 0xfb, 0xc3, + 0x0c, 0xd4, 0x75, 0xbb, 0x06, 0x3d, 0x81, 0x46, 0xdc, 0x42, 0x45, 0xb7, 0x13, 0xb0, 0xd9, 0xfe, + 0xac, 0xb1, 0x96, 0xcf, 0xd4, 0x09, 0x38, 0x80, 0x39, 0xd5, 0xc2, 0xdc, 0x28, 0xea, 0x09, 0x69, + 0x98, 0xcd, 0x42, 0xbe, 0x46, 0x3a, 0x87, 0x4e, 0xba, 0x0b, 0x85, 0xee, 0x17, 0xa8, 0x64, 0xef, + 0x40, 0x63, 0xfb, 0xe5, 0x82, 0xca, 0xc8, 0x9e, 0x0f, 0x8d, 0xb8, 0x81, 0x84, 0x30, 0xb4, 0x92, + 0x4d, 0xa4, 0x94, 0xbd, 0x49, 0x8d, 0xab, 0x94, 0xbd, 0x89, 0xfd, 0xa8, 0xbd, 0xaf, 0xab, 0x30, + 0x2b, 0xd2, 0x8b, 0x3e, 0x84, 0xba, 0x6e, 0x20, 0xa1, 0xd5, 0x84, 0x76, 0xba, 0x31, 0x65, 0x18, + 0x79, 0x2c, 0x1d, 0x9f, 0x23, 0x68, 0x26, 0xba, 0x41, 0x68, 0x3d, 0x21, 0x3a, 0xde, 0x6d, 0x32, + 0x36, 0x8a, 0xd8, 0x1a, 0xed, 0x10, 0x60, 0xd4, 0x14, 0x41, 0x6b, 0x05, 0xbd, 0x12, 0x85, 0xb5, + 0x3e, 0xb1, 0x93, 0x82, 0x9e, 0xc3, 0xe2, 0x58, 0x07, 0x01, 0xdd, 0x99, 0xdc, 0x5f, 0x50, 0xc0, + 0x77, 0x6f, 0xd2, 0x84, 0x40, 0x0f, 0x61, 0x3e, 0x2a, 0xeb, 0x51, 0x32, 0x40, 0x99, 0x86, 0x81, + 0x71, 0x3b, 0x97, 0xa7, 0x13, 0xf1, 0xaf, 0x86, 0xbc, 0x24, 0xe8, 0x90, 0x33, 0x91, 0x8b, 0x28, + 0xe5, 0xc9, 0x5c, 0x64, 0x92, 0x6c, 0xe4, 0xb1, 0xb4, 0x4b, 0x16, 0xb4, 0x53, 0xb5, 0x19, 0xda, + 0x1c, 0x17, 0x4e, 0xdd, 0xd3, 0xc6, 0x56, 0xb1, 0x40, 0xdc, 0xad, 0x59, 0xc8, 0xd6, 0x0a, 0xc8, + 0x1c, 0xd7, 0x1a, 0x5b, 0xfc, 0x77, 0x26, 0xca, 0x68, 0xf0, 0x01, 0x2c, 0xe7, 0x17, 0x22, 0x68, + 0x7b, 0x82, 0x7a, 0x7a, 0x0a, 0x6f, 0xde, 0x40, 0x52, 0x9b, 0xfb, 0x29, 0xd4, 0xd4, 0x23, 0x1c, + 0xf5, 0xc6, 0xde, 0xee, 0x11, 0xdc, 0x6a, 0x0e, 0x47, 0xab, 0x7f, 0x3a, 0xfe, 0x86, 0xff, 0xfe, + 0x84, 0x1a, 0x40, 0x03, 0x9a, 0x93, 0x44, 0x34, 0x32, 0x83, 0x5e, 0x51, 0xbb, 0x04, 0xfd, 0x20, + 0xa9, 0x3f, 0xb9, 0xb7, 0x63, 0xbc, 0x75, 0x23, 0xd9, 0xc4, 0x74, 0xd2, 0x32, 0xe9, 0xe9, 0xe4, + 0x36, 0x5b, 0xd2, 0xd3, 0x29, 0xe8, 0xa1, 0x58, 0xd0, 0x4e, 0x95, 0x11, 0xa9, 0x75, 0x98, 0x57, + 0xaa, 0xa4, 0xd6, 0x61, 0x7e, 0x05, 0xf2, 0x39, 0x2c, 0x64, 0x1f, 0x75, 0xa9, 0x75, 0x58, 0x50, + 0x88, 0xa4, 0xd6, 0x61, 0x61, 0xb1, 0xf0, 0xe1, 0xe8, 0xa9, 0xb6, 0x9a, 0xf3, 0x12, 0xcc, 0xd9, + 0x7a, 0xd9, 0x97, 0xbe, 0x05, 0xed, 0xd4, 0xcb, 0x3a, 0x35, 0xe5, 0xbc, 0x57, 0x7d, 0x6a, 0xca, + 0xf9, 0x8f, 0xf2, 0x01, 0x2c, 0xe7, 0xbf, 0x63, 0x53, 0xbb, 0x63, 0xe2, 0x43, 0x3c, 0xb5, 0x3b, + 0x5e, 0xf2, 0x28, 0x7e, 0x9e, 0xf7, 0x46, 0xb8, 0x33, 0xf9, 0x6a, 0x1f, 0x3f, 0x30, 0x0b, 0xef, + 0xff, 0xfd, 0xbb, 0x9f, 0x99, 0x82, 0xf0, 0x9b, 0x1d, 0x97, 0xee, 0xca, 0x8f, 0xdd, 0x20, 0x74, + 0xaf, 0x30, 0x27, 0xbb, 0xb1, 0x76, 0x70, 0x76, 0x56, 0x93, 0x3f, 0x0a, 0xde, 0xfd, 0x6f, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x19, 0x6b, 0x49, 0x96, 0x07, 0x1e, 0x00, 0x00, } diff --git a/private/multinodepb/multinode.proto b/private/multinodepb/multinode.proto index c7585bb74..a54ed3e5f 100644 --- a/private/multinodepb/multinode.proto +++ b/private/multinodepb/multinode.proto @@ -15,6 +15,8 @@ message RequestHeader { service Storage { rpc DiskSpace(DiskSpaceRequest) returns (DiskSpaceResponse); + rpc Usage(StorageUsageRequest) returns (StorageUsageResponse); + rpc UsageSatellite(StorageUsageSatelliteRequest) returns (StorageUsageSatelliteResponse); } message DiskSpaceRequest { @@ -30,6 +32,32 @@ message DiskSpaceResponse { int64 overused = 6; } +message StorageUsage { + double at_rest_total = 1; + google.protobuf.Timestamp interval_start = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; +} + +message StorageUsageRequest { + RequestHeader header = 1; + google.protobuf.Timestamp from = 2 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + google.protobuf.Timestamp to = 3 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; +} + +message StorageUsageResponse { + repeated StorageUsage storage_usage = 1; +} + +message StorageUsageSatelliteRequest { + RequestHeader header = 1; + bytes satellite_id = 2 [(gogoproto.customtype) = "NodeID", (gogoproto.nullable) = false]; + google.protobuf.Timestamp from = 3 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; + google.protobuf.Timestamp to = 4 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false]; +} + +message StorageUsageSatelliteResponse { + repeated StorageUsage storage_usage = 1; +} + service Bandwidth { rpc MonthSummary(BandwidthMonthSummaryRequest) returns (BandwidthMonthSummaryResponse); } diff --git a/private/multinodepb/multinode_drpc.pb.go b/private/multinodepb/multinode_drpc.pb.go index db54903d9..c5eb808ca 100644 --- a/private/multinodepb/multinode_drpc.pb.go +++ b/private/multinodepb/multinode_drpc.pb.go @@ -43,6 +43,8 @@ type DRPCStorageClient interface { DRPCConn() drpc.Conn DiskSpace(ctx context.Context, in *DiskSpaceRequest) (*DiskSpaceResponse, error) + Usage(ctx context.Context, in *StorageUsageRequest) (*StorageUsageResponse, error) + UsageSatellite(ctx context.Context, in *StorageUsageSatelliteRequest) (*StorageUsageSatelliteResponse, error) } type drpcStorageClient struct { @@ -64,8 +66,28 @@ func (c *drpcStorageClient) DiskSpace(ctx context.Context, in *DiskSpaceRequest) return out, nil } +func (c *drpcStorageClient) Usage(ctx context.Context, in *StorageUsageRequest) (*StorageUsageResponse, error) { + out := new(StorageUsageResponse) + err := c.cc.Invoke(ctx, "/multinode.Storage/Usage", drpcEncoding_File_multinode_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *drpcStorageClient) UsageSatellite(ctx context.Context, in *StorageUsageSatelliteRequest) (*StorageUsageSatelliteResponse, error) { + out := new(StorageUsageSatelliteResponse) + err := c.cc.Invoke(ctx, "/multinode.Storage/UsageSatellite", drpcEncoding_File_multinode_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + type DRPCStorageServer interface { DiskSpace(context.Context, *DiskSpaceRequest) (*DiskSpaceResponse, error) + Usage(context.Context, *StorageUsageRequest) (*StorageUsageResponse, error) + UsageSatellite(context.Context, *StorageUsageSatelliteRequest) (*StorageUsageSatelliteResponse, error) } type DRPCStorageUnimplementedServer struct{} @@ -74,9 +96,17 @@ func (s *DRPCStorageUnimplementedServer) DiskSpace(context.Context, *DiskSpaceRe return nil, drpcerr.WithCode(errors.New("Unimplemented"), 12) } +func (s *DRPCStorageUnimplementedServer) Usage(context.Context, *StorageUsageRequest) (*StorageUsageResponse, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), 12) +} + +func (s *DRPCStorageUnimplementedServer) UsageSatellite(context.Context, *StorageUsageSatelliteRequest) (*StorageUsageSatelliteResponse, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), 12) +} + type DRPCStorageDescription struct{} -func (DRPCStorageDescription) NumMethods() int { return 1 } +func (DRPCStorageDescription) NumMethods() int { return 3 } func (DRPCStorageDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) { switch n { @@ -89,6 +119,24 @@ func (DRPCStorageDescription) Method(n int) (string, drpc.Encoding, drpc.Receive in1.(*DiskSpaceRequest), ) }, DRPCStorageServer.DiskSpace, true + case 1: + return "/multinode.Storage/Usage", drpcEncoding_File_multinode_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCStorageServer). + Usage( + ctx, + in1.(*StorageUsageRequest), + ) + }, DRPCStorageServer.Usage, true + case 2: + return "/multinode.Storage/UsageSatellite", drpcEncoding_File_multinode_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCStorageServer). + UsageSatellite( + ctx, + in1.(*StorageUsageSatelliteRequest), + ) + }, DRPCStorageServer.UsageSatellite, true default: return "", nil, nil, nil, false } @@ -114,6 +162,38 @@ func (x *drpcStorage_DiskSpaceStream) SendAndClose(m *DiskSpaceResponse) error { return x.CloseSend() } +type DRPCStorage_UsageStream interface { + drpc.Stream + SendAndClose(*StorageUsageResponse) error +} + +type drpcStorage_UsageStream struct { + drpc.Stream +} + +func (x *drpcStorage_UsageStream) SendAndClose(m *StorageUsageResponse) error { + if err := x.MsgSend(m, drpcEncoding_File_multinode_proto{}); err != nil { + return err + } + return x.CloseSend() +} + +type DRPCStorage_UsageSatelliteStream interface { + drpc.Stream + SendAndClose(*StorageUsageSatelliteResponse) error +} + +type drpcStorage_UsageSatelliteStream struct { + drpc.Stream +} + +func (x *drpcStorage_UsageSatelliteStream) SendAndClose(m *StorageUsageSatelliteResponse) error { + if err := x.MsgSend(m, drpcEncoding_File_multinode_proto{}); err != nil { + return err + } + return x.CloseSend() +} + type DRPCBandwidthClient interface { DRPCConn() drpc.Conn diff --git a/storagenode/multinode/storage.go b/storagenode/multinode/storage.go index 76b16f1e2..9f23e9819 100644 --- a/storagenode/multinode/storage.go +++ b/storagenode/multinode/storage.go @@ -6,12 +6,14 @@ package multinode import ( "context" + "github.com/zeebo/errs" "go.uber.org/zap" "storj.io/common/rpc/rpcstatus" "storj.io/storj/private/multinodepb" "storj.io/storj/storagenode/apikeys" "storj.io/storj/storagenode/monitor" + "storj.io/storj/storagenode/storageusage" ) var _ multinodepb.DRPCStorageServer = (*StorageEndpoint)(nil) @@ -25,14 +27,16 @@ type StorageEndpoint struct { log *zap.Logger apiKeys *apikeys.Service monitor *monitor.Service + usage storageusage.DB } // NewStorageEndpoint creates new multinode storage endpoint. -func NewStorageEndpoint(log *zap.Logger, apiKeys *apikeys.Service, monitor *monitor.Service) *StorageEndpoint { +func NewStorageEndpoint(log *zap.Logger, apiKeys *apikeys.Service, monitor *monitor.Service, usage storageusage.DB) *StorageEndpoint { return &StorageEndpoint{ log: log, apiKeys: apiKeys, monitor: monitor, + usage: usage, } } @@ -59,3 +63,77 @@ func (storage *StorageEndpoint) DiskSpace(ctx context.Context, req *multinodepb. Overused: diskSpace.Overused, }, nil } + +// Usage returns daily storage usage for a given interval. +func (storage *StorageEndpoint) Usage(ctx context.Context, req *multinodepb.StorageUsageRequest) (_ *multinodepb.StorageUsageResponse, err error) { + defer mon.Task()(&ctx)(&err) + + if err = authenticate(ctx, storage.apiKeys, req.GetHeader()); err != nil { + return nil, rpcstatus.Wrap(rpcstatus.Unauthenticated, err) + } + + from := req.GetFrom() + if from.IsZero() { + return nil, rpcstatus.Wrap(rpcstatus.InvalidArgument, errs.New("from timestamp is not provided")) + } + to := req.GetTo() + if to.IsZero() { + return nil, rpcstatus.Wrap(rpcstatus.InvalidArgument, errs.New("to timestamp is not provided")) + } + + stamps, err := storage.usage.GetDailyTotal(ctx, from, to) + if err != nil { + return nil, rpcstatus.Wrap(rpcstatus.Internal, err) + } + + var usage []*multinodepb.StorageUsage + for _, stamp := range stamps { + usage = append(usage, &multinodepb.StorageUsage{ + AtRestTotal: stamp.AtRestTotal, + IntervalStart: stamp.IntervalStart, + }) + } + + return &multinodepb.StorageUsageResponse{ + StorageUsage: usage, + }, nil +} + +// UsageSatellite returns daily storage usage for a given interval and satellite. +func (storage *StorageEndpoint) UsageSatellite(ctx context.Context, req *multinodepb.StorageUsageSatelliteRequest) (_ *multinodepb.StorageUsageSatelliteResponse, err error) { + defer mon.Task()(&ctx)(&err) + + if err = authenticate(ctx, storage.apiKeys, req.GetHeader()); err != nil { + return nil, rpcstatus.Wrap(rpcstatus.Unauthenticated, err) + } + + if req.SatelliteId.IsZero() { + return nil, rpcstatus.Wrap(rpcstatus.InvalidArgument, errs.New("satellite id is not provided")) + } + + from := req.GetFrom() + if from.IsZero() { + return nil, rpcstatus.Wrap(rpcstatus.InvalidArgument, errs.New("from timestamp is not provided")) + } + to := req.GetTo() + if to.IsZero() { + return nil, rpcstatus.Wrap(rpcstatus.InvalidArgument, errs.New("to timestamp is not provided")) + } + + stamps, err := storage.usage.GetDaily(ctx, req.SatelliteId, from, to) + if err != nil { + return nil, rpcstatus.Wrap(rpcstatus.Internal, err) + } + + var usage []*multinodepb.StorageUsage + for _, stamp := range stamps { + usage = append(usage, &multinodepb.StorageUsage{ + AtRestTotal: stamp.AtRestTotal, + IntervalStart: stamp.IntervalStart, + }) + } + + return &multinodepb.StorageUsageSatelliteResponse{ + StorageUsage: usage, + }, nil +} diff --git a/storagenode/peer.go b/storagenode/peer.go index 47d550b52..756c9883d 100644 --- a/storagenode/peer.go +++ b/storagenode/peer.go @@ -787,6 +787,7 @@ func New(log *zap.Logger, full *identity.FullIdentity, db DB, revocationDB exten peer.Log.Named("multinode:storage-endpoint"), apiKeys, peer.Storage2.Monitor, + peer.DB.StorageUsage(), ) peer.Multinode.Bandwidth = multinode.NewBandwidthEndpoint(