1// Copyright (C) 2020 Storj Labs, Inc.
2// See LICENSE for copying information.
3
4package metabase
5
6import (
7	"context"
8	"time"
9
10	"storj.io/common/storj"
11	"storj.io/common/uuid"
12)
13
14// ObjectEntry contains information about an item in a bucket.
15type ObjectEntry struct {
16	IsPrefix bool
17
18	ObjectKey ObjectKey
19	Version   Version
20	StreamID  uuid.UUID
21
22	CreatedAt time.Time
23	ExpiresAt *time.Time
24
25	Status       ObjectStatus
26	SegmentCount int32
27
28	EncryptedMetadataNonce        []byte
29	EncryptedMetadata             []byte
30	EncryptedMetadataEncryptedKey []byte
31
32	TotalPlainSize     int64
33	TotalEncryptedSize int64
34	FixedSegmentSize   int32
35
36	Encryption storj.EncryptionParameters
37}
38
39// ObjectsIterator iterates over a sequence of ObjectEntry items.
40type ObjectsIterator interface {
41	Next(ctx context.Context, item *ObjectEntry) bool
42}
43
44// IterateCursor is a cursor used during iteration through objects.
45//
46// The cursor is exclusive.
47type IterateCursor struct {
48	Key     ObjectKey
49	Version Version
50}
51
52// StreamIDCursor is a cursor used during iteration through streamIDs of a pending object.
53type StreamIDCursor struct {
54	StreamID uuid.UUID
55}
56
57// IterateObjects contains arguments necessary for listing objects in a bucket.
58type IterateObjects struct {
59	ProjectID  uuid.UUID
60	BucketName string
61	BatchSize  int
62	Prefix     ObjectKey
63	Cursor     IterateCursor
64}
65
66// Verify verifies get object request fields.
67func (opts *IterateObjects) Verify() error {
68	switch {
69	case opts.ProjectID.IsZero():
70		return ErrInvalidRequest.New("ProjectID missing")
71	case opts.BucketName == "":
72		return ErrInvalidRequest.New("BucketName missing")
73	case opts.BatchSize < 0:
74		return ErrInvalidRequest.New("BatchSize is negative")
75	}
76	return nil
77}
78
79// IterateObjectsAllVersions iterates through all versions of all objects.
80func (db *DB) IterateObjectsAllVersions(ctx context.Context, opts IterateObjects, fn func(context.Context, ObjectsIterator) error) (err error) {
81	defer mon.Task()(&ctx)(&err)
82	if err = opts.Verify(); err != nil {
83		return err
84	}
85	return iterateAllVersions(ctx, db, opts, fn)
86}
87
88// IteratePendingObjectsByKey contains arguments necessary for listing pending objects by ObjectKey.
89type IteratePendingObjectsByKey struct {
90	ObjectLocation
91	BatchSize int
92	Cursor    StreamIDCursor
93}
94
95// IterateObjectsWithStatus contains arguments necessary for listing objects in a bucket.
96type IterateObjectsWithStatus struct {
97	ProjectID             uuid.UUID
98	BucketName            string
99	Recursive             bool
100	BatchSize             int
101	Prefix                ObjectKey
102	Cursor                IterateCursor
103	Status                ObjectStatus
104	IncludeCustomMetadata bool
105	IncludeSystemMetadata bool
106}
107
108// IterateObjectsAllVersionsWithStatus iterates through all versions of all objects with specified status.
109func (db *DB) IterateObjectsAllVersionsWithStatus(ctx context.Context, opts IterateObjectsWithStatus, fn func(context.Context, ObjectsIterator) error) (err error) {
110	defer mon.Task()(&ctx)(&err)
111	if err = opts.Verify(); err != nil {
112		return err
113	}
114	return iterateAllVersionsWithStatus(ctx, db, opts, fn)
115}
116
117// Verify verifies get object request fields.
118func (opts *IterateObjectsWithStatus) Verify() error {
119	switch {
120	case opts.ProjectID.IsZero():
121		return ErrInvalidRequest.New("ProjectID missing")
122	case opts.BucketName == "":
123		return ErrInvalidRequest.New("BucketName missing")
124	case opts.BatchSize < 0:
125		return ErrInvalidRequest.New("BatchSize is negative")
126	case !(opts.Status == Pending || opts.Status == Committed):
127		return ErrInvalidRequest.New("Status %v is not supported", opts.Status)
128	}
129	return nil
130}
131
132// IteratePendingObjectsByKey iterates through all streams of pending objects with the same ObjectKey.
133func (db *DB) IteratePendingObjectsByKey(ctx context.Context, opts IteratePendingObjectsByKey, fn func(context.Context, ObjectsIterator) error) (err error) {
134	defer mon.Task()(&ctx)(&err)
135
136	if err := opts.Verify(); err != nil {
137		return err
138	}
139	return iteratePendingObjectsByKey(ctx, db, opts, fn)
140}
141
142// Verify verifies get object request fields.
143func (opts *IteratePendingObjectsByKey) Verify() error {
144	if err := opts.ObjectLocation.Verify(); err != nil {
145		return err
146	}
147	if opts.BatchSize < 0 {
148		return ErrInvalidRequest.New("BatchSize is negative")
149	}
150	return nil
151}
152