func (p *CAS) WriteWithCIDFormat(content []byte, opts ...extendedcasclient.CIDFormatOption) (string, error) {
	if len(content) == 0 {
		return "", errors.New("empty content")
	}
	resourceHash, err := p.hl.CreateResourceHash(content)
	if err != nil {
		return "", fmt.Errorf("failed to create resource hash from content: %w", err)
	}
	if log.IsEnabledFor(logModule, log.DEBUG) {
		logger.Debugf("Writing to CAS store [%s]. Content (base64-encoded): %s",
			resourceHash, base64.RawStdEncoding.EncodeToString(content))
	}
	err = p.cas.Put(resourceHash, content)
	if err != nil {
		return "", orberrors.NewTransient(fmt.Errorf("failed to put content into underlying storage provider: %w", err))
	}
	links := []string{p.casLink + "/" + resourceHash}
	if p.ipfsClient != nil {
		cid, writeErr := p.ipfsClient.WriteWithCIDFormat(content, opts...)
		if writeErr != nil {
			return "", orberrors.NewTransient(fmt.Errorf("failed to put content into IPFS (but it was "+
				"successfully stored in the local storage provider): %w", writeErr))
		}
		links = append(links, "ipfs://"+cid)
	}
	if err = p.cache.Set(resourceHash, content); err != nil {
		logger.Warnf("Error caching content for resource hash[%s]: %s", resourceHash, err)
	} else {
		logger.Debugf("Cached content for resource hash [%s]", resourceHash)
	}
	metadata, err := p.hl.CreateMetadataFromLinks(links)
	if err != nil {
		return "", fmt.Errorf("failed to create resource hash from content: %w", err)
	}
	return hashlink.GetHashLink(resourceHash, metadata), nil
}
WriteWithCIDFormat writes the given content to the underlying local CAS provider (and IPFS if configured) using the
CID format specified by opts.
Returns the address of the content.
TODO (#418): Support creating IPFS-compatible CIDs when content is > 256KB.
TODO (#443): Support v1 CID formats (different multibases and multicodecs) other than just the IPFS default.
package cas
import (
	"encoding/base64"
	"errors"
	"fmt"
	"time"
	"github.com/bluele/gcache"
	ariesstorage "github.com/hyperledger/aries-framework-go/spi/storage"
	"github.com/trustbloc/edge-core/pkg/log"
	"github.com/trustbloc/orb/pkg/cas/extendedcasclient"
	"github.com/trustbloc/orb/pkg/cas/ipfs"
	orberrors "github.com/trustbloc/orb/pkg/errors"
	"github.com/trustbloc/orb/pkg/hashlink"
)
const logModule = "cas-store"
var logger = log.New(logModule)
const (
	defaultCacheSize = 1000
	casType          = "local"
)
type metricsProvider interface {
	CASIncrementCacheHitCount()
	CASReadTime(casType string, value time.Duration)
}
type CAS struct {
	cas        ariesstorage.Store
	ipfsClient *ipfs.Client
	opts       []extendedcasclient.CIDFormatOption
	cache      gcache.Cache
	metrics    metricsProvider
	casLink    string
	hl         *hashlink.HashLink
}
func New(provider ariesstorage.Provider, casLink string, ipfsClient *ipfs.Client,
	metrics metricsProvider, cacheSize int, opts ...extendedcasclient.CIDFormatOption) (*CAS, error) {
	cas, err := provider.OpenStore("cas_store")
	if err != nil {
		return nil, fmt.Errorf("failed to open store in underlying storage provider: %w", err)
	}
	if cacheSize == 0 {
		cacheSize = defaultCacheSize
	}
	c := &CAS{
		cas:        cas,
		ipfsClient: ipfsClient,
		opts:       opts,
		metrics:    metrics,
		hl:         hashlink.New(),
		casLink:    casLink,
	}
	c.cache = gcache.New(cacheSize).ARC().
		LoaderFunc(func(key interface{}) (interface{}, error) {
			cid, err := c.get(key.(string))
			if err != nil {
				return nil, err
			}
			logger.Debugf("Content was cached for key [%s]", key)
			return cid, nil
		},
		).Build()
	return c, nil
}
func (p *CAS) Write(content []byte) (string, error) {
	return p.WriteWithCIDFormat(content, p.opts...)
}