2020-10-01 23:52:22 +01:00
|
|
|
// Copyright (C) 2020 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package ordersfile
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/binary"
|
|
|
|
"errors"
|
|
|
|
"io"
|
2020-11-16 16:13:54 +00:00
|
|
|
"math"
|
2020-10-01 23:52:22 +01:00
|
|
|
"os"
|
|
|
|
|
|
|
|
"storj.io/common/pb"
|
|
|
|
)
|
|
|
|
|
|
|
|
// fileV0 is a version 0 orders file.
|
|
|
|
type fileV0 struct {
|
2020-10-06 17:14:25 +01:00
|
|
|
f *os.File
|
|
|
|
}
|
|
|
|
|
|
|
|
// OpenWritableV0 opens for writing the unsent or archived orders file at a given path.
|
|
|
|
func OpenWritableV0(path string) (Writable, error) {
|
|
|
|
// create file if not exists or append
|
|
|
|
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|
|
|
if err != nil {
|
|
|
|
return nil, Error.Wrap(err)
|
|
|
|
}
|
|
|
|
return &fileV0{
|
|
|
|
f: f,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// OpenReadableV0 opens for reading the unsent or archived orders file at a given path.
|
|
|
|
func OpenReadableV0(path string) (Readable, error) {
|
|
|
|
f, err := os.Open(path)
|
|
|
|
if err != nil {
|
|
|
|
return nil, Error.Wrap(err)
|
|
|
|
}
|
|
|
|
return &fileV0{
|
|
|
|
f: f,
|
|
|
|
}, nil
|
2020-10-01 23:52:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// Append writes limit and order to the file as
|
|
|
|
// [limitSize][limitBytes][orderSize][orderBytes].
|
|
|
|
func (of *fileV0) Append(info *Info) error {
|
|
|
|
toWrite := []byte{}
|
|
|
|
|
|
|
|
limitSerialized, err := pb.Marshal(info.Limit)
|
|
|
|
if err != nil {
|
|
|
|
return Error.Wrap(err)
|
|
|
|
}
|
|
|
|
orderSerialized, err := pb.Marshal(info.Order)
|
|
|
|
if err != nil {
|
|
|
|
return Error.Wrap(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
limitSizeBytes := [4]byte{}
|
|
|
|
binary.LittleEndian.PutUint32(limitSizeBytes[:], uint32(len(limitSerialized)))
|
|
|
|
|
|
|
|
orderSizeBytes := [4]byte{}
|
|
|
|
binary.LittleEndian.PutUint32(orderSizeBytes[:], uint32(len(orderSerialized)))
|
|
|
|
|
|
|
|
toWrite = append(toWrite, limitSizeBytes[:]...)
|
|
|
|
toWrite = append(toWrite, limitSerialized...)
|
|
|
|
toWrite = append(toWrite, orderSizeBytes[:]...)
|
|
|
|
toWrite = append(toWrite, orderSerialized...)
|
|
|
|
|
|
|
|
if _, err = of.f.Write(toWrite); err != nil {
|
|
|
|
return Error.New("Couldn't write serialized order and limit: %w", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ReadOne reads one entry from the file.
|
|
|
|
func (of *fileV0) ReadOne() (info *Info, err error) {
|
|
|
|
defer func() {
|
|
|
|
if errors.Is(err, io.ErrUnexpectedEOF) {
|
2020-10-06 17:14:25 +01:00
|
|
|
err = ErrEntryCorrupt.Wrap(err)
|
2020-10-01 23:52:22 +01:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
sizeBytes := [4]byte{}
|
|
|
|
_, err = io.ReadFull(of.f, sizeBytes[:])
|
|
|
|
if err != nil {
|
|
|
|
return nil, Error.Wrap(err)
|
|
|
|
}
|
|
|
|
limitSize := binary.LittleEndian.Uint32(sizeBytes[:])
|
2020-11-16 16:13:54 +00:00
|
|
|
if limitSize > uint32(math.MaxInt32) {
|
|
|
|
return nil, ErrEntryCorrupt.New("invalid limit's size; %d is over the maximum %d", limitSize, math.MaxInt32)
|
|
|
|
}
|
|
|
|
|
2020-10-01 23:52:22 +01:00
|
|
|
limitSerialized := make([]byte, limitSize)
|
|
|
|
_, err = io.ReadFull(of.f, limitSerialized)
|
|
|
|
if err != nil {
|
|
|
|
return nil, Error.Wrap(err)
|
|
|
|
}
|
|
|
|
limit := &pb.OrderLimit{}
|
|
|
|
err = pb.Unmarshal(limitSerialized, limit)
|
|
|
|
if err != nil {
|
2020-10-26 18:28:59 +00:00
|
|
|
// if there is an error unmarshalling, the file must be corrupt
|
|
|
|
return nil, ErrEntryCorrupt.Wrap(err)
|
2020-10-01 23:52:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
_, err = io.ReadFull(of.f, sizeBytes[:])
|
|
|
|
if err != nil {
|
|
|
|
return nil, Error.Wrap(err)
|
|
|
|
}
|
|
|
|
orderSize := binary.LittleEndian.Uint32(sizeBytes[:])
|
2020-11-16 16:13:54 +00:00
|
|
|
if orderSize > uint32(math.MaxInt32) {
|
2020-11-17 14:22:27 +00:00
|
|
|
return nil, ErrEntryCorrupt.New("invalid order's size; %d is over the maximum %d", orderSize, math.MaxInt32)
|
2020-11-16 16:13:54 +00:00
|
|
|
}
|
|
|
|
|
2020-10-01 23:52:22 +01:00
|
|
|
orderSerialized := make([]byte, orderSize)
|
|
|
|
_, err = io.ReadFull(of.f, orderSerialized)
|
|
|
|
if err != nil {
|
|
|
|
return nil, Error.Wrap(err)
|
|
|
|
}
|
|
|
|
order := &pb.Order{}
|
|
|
|
err = pb.Unmarshal(orderSerialized, order)
|
|
|
|
if err != nil {
|
2020-10-26 15:48:12 +00:00
|
|
|
// if there is an error unmarshalling, the file must be corrupt
|
|
|
|
return nil, ErrEntryCorrupt.Wrap(err)
|
2020-10-01 23:52:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return &Info{
|
|
|
|
Limit: limit,
|
|
|
|
Order: order,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close closes the file.
|
|
|
|
func (of *fileV0) Close() error {
|
|
|
|
return of.f.Close()
|
|
|
|
}
|