func (t *Tag) WaitTillDone(ctx context.Context, s State) error {
	if t.Done(s) {
		return nil
	}
	ticker := time.NewTicker(100 * time.Millisecond)
	for {
		select {
		case <-ticker.C:
			if t.Done(s) {
				return nil
			}
		case <-ctx.Done():
			return ctx.Err()
		}
	}
}
WaitTillDone returns without error once the tag is complete
wrt the state given as argument
it returns an error if the context is done
package tags
import (
	"context"
	"encoding/binary"
	"errors"
	"fmt"
	"sync"
	"sync/atomic"
	"time"
	"github.com/ethsana/sana/pkg/logging"
	"github.com/ethsana/sana/pkg/storage"
	"github.com/ethsana/sana/pkg/swarm"
	"github.com/ethsana/sana/pkg/tracing"
	"github.com/opentracing/opentracing-go"
)
var (
	errExists = errors.New("already exists")
	errNA     = errors.New("not available yet")
	errNoETA  = errors.New("unable to calculate ETA")
)
type State = uint32
const (
	TotalChunks State = iota  
	StateSplit                
	StateStored               
	StateSeen                 
	StateSent                 
	StateSynced               
)
type Tag struct {
	Total  int64  
	Split  int64  
	Seen   int64  
	Stored int64  
	Sent   int64  
	Synced int64  
	Uid       uint32         
	Address   swarm.Address  
	StartedAt time.Time      
	ctx        context.Context      
	span       opentracing.Span     
	spanOnce   sync.Once            
	stateStore storage.StateStorer  
	logger     logging.Logger       
}
func NewTag(ctx context.Context, uid uint32, total int64, tracer *tracing.Tracer, stateStore storage.StateStorer, logger logging.Logger) *Tag {
	t := &Tag{
		Uid:        uid,
		StartedAt:  time.Now(),
		Total:      total,
		stateStore: stateStore,
		logger:     logger,
	}
	t.span, _, t.ctx = tracer.StartSpanFromContext(ctx, "new.upload.tag", nil)
	return t
}
func (t *Tag) Context() context.Context {
	return t.ctx
}
func (t *Tag) FinishRootSpan() {
	t.spanOnce.Do(func() {
		t.span.Finish()
	})
}
func (t *Tag) IncN(state State, n int64) error {
	var v *int64
	switch state {
	case TotalChunks:
		v = &t.Total
	case StateSplit:
		v = &t.Split
	case StateStored:
		v = &t.Stored
	case StateSeen:
		v = &t.Seen
	case StateSent:
		v = &t.Sent
	case StateSynced:
		v = &t.Synced
	}
	atomic.AddInt64(v, n)
	if state == StateSynced {
		total := atomic.LoadInt64(&t.Total)
		seen := atomic.LoadInt64(&t.Seen)
		synced := atomic.LoadInt64(&t.Synced)
		totalUnique := total - seen
		if synced >= totalUnique {
			return t.saveTag()
		}
	}
	return nil
}
func (t *Tag) Inc(state State) error {
	return t.IncN(state, 1)
}
func (t *Tag) Get(state State) int64 {
	var v *int64
	switch state {
	case TotalChunks:
		v = &t.Total
	case StateSplit:
		v = &t.Split
	case StateStored:
		v = &t.Stored
	case StateSeen:
		v = &t.Seen
	case StateSent:
		v = &t.Sent
	case StateSynced:
		v = &t.Synced
	}
	return atomic.LoadInt64(v)
}
func (t *Tag) TotalCounter() int64 {
	return atomic.LoadInt64(&t.Total)
}