storj/pkg/piecestore/psserver/store.go

136 lines
3.1 KiB
Go
Raw Normal View History

2019-01-24 20:15:10 +00:00
// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package psserver
import (
"context"
"fmt"
"io"
"time"
"github.com/zeebo/errs"
"go.uber.org/zap"
"storj.io/storj/pkg/auth"
"storj.io/storj/pkg/pb"
"storj.io/storj/pkg/utils"
)
// OK - Success!
const OK = "OK"
// StoreError is a type of error for failures in Server.Store()
var StoreError = errs.Class("store error")
// Store incoming data using piecestore
func (s *Server) Store(reqStream pb.PieceStoreRoutes_StoreServer) (err error) {
ctx := reqStream.Context()
defer mon.Task()(&ctx)(&err)
// Receive id/ttl
recv, err := reqStream.Recv()
if err != nil {
return StoreError.Wrap(err)
}
if recv == nil {
return StoreError.New("error receiving Piece metadata")
}
pd := recv.GetPieceData()
if pd == nil {
return StoreError.New("PieceStore message is nil")
}
s.log.Debug("Storing", zap.String("Piece ID", fmt.Sprint(pd.GetId())))
if pd.GetId() == "" {
return StoreError.New("piece ID not specified")
}
rba := recv.GetBandwidthAllocation()
if rba == nil {
return StoreError.New("Order message is nil")
}
pba := rba.PayerAllocation
if pb.Equal(&pba, &pb.OrderLimit{}) {
return StoreError.New("OrderLimit message is empty")
}
id, err := getNamespacedPieceID([]byte(pd.GetId()), pba.SatelliteId.Bytes())
if err != nil {
return err
}
total, hash, err := s.storeData(ctx, reqStream, id)
if err != nil {
return err
}
if err = s.DB.AddTTL(id, pd.GetExpirationUnixSec(), total); err != nil {
deleteErr := s.deleteByID(id)
return StoreError.New("failed to write piece meta data to database: %v", utils.CombineErrors(err, deleteErr))
}
signedHash := &pb.SignedHash{Hash: hash}
err = auth.SignMessage(signedHash, *s.identity)
if err != nil {
return err
}
s.log.Info("Successfully stored", zap.String("Piece ID", fmt.Sprint(pd.GetId())))
return reqStream.SendAndClose(&pb.PieceStoreSummary{
Message: OK,
TotalReceived: total,
SignedHash: signedHash,
})
}
func (s *Server) storeData(ctx context.Context, stream pb.PieceStoreRoutes_StoreServer, id string) (total int64, hash []byte, err error) {
defer mon.Task()(&ctx)(&err)
// Delete data if we error
defer func() {
if err != nil && err != io.EOF {
if deleteErr := s.deleteByID(id); deleteErr != nil {
s.log.Error("Failed on deleteByID in Store", zap.Error(deleteErr))
}
}
}()
// Initialize file for storing data
storeFile, err := s.storage.Writer(id)
if err != nil {
return 0, nil, err
}
defer func() {
err = errs.Combine(err, storeFile.Close())
}()
bwUsed, err := s.DB.GetTotalBandwidthBetween(getBeginningOfMonth(), time.Now())
if err != nil {
return 0, nil, err
}
spaceUsed, err := s.DB.SumTTLSizes()
if err != nil {
return 0, nil, err
}
bwLeft := s.totalBwAllocated - bwUsed
spaceLeft := s.totalAllocated - spaceUsed
reader := NewStreamReader(s, stream, bwLeft, spaceLeft)
total, err = io.Copy(storeFile, reader)
if err != nil && err != io.EOF {
return 0, nil, err
}
err = s.DB.WriteBandwidthAllocToDB(reader.bandwidthAllocation)
if err != nil {
return 0, nil, err
}
hash = reader.hash.Sum(nil)
return total, hash, nil
}