github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/repo/mem_repo.go (about)

     1  package repo
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"sync"
     7  
     8  	"github.com/qri-io/qfs"
     9  	"github.com/qri-io/qfs/muxfs"
    10  	"github.com/qri-io/qri/auth/key"
    11  	"github.com/qri-io/qri/dscache"
    12  	"github.com/qri-io/qri/dsref"
    13  	"github.com/qri-io/qri/event"
    14  	"github.com/qri-io/qri/logbook"
    15  	"github.com/qri-io/qri/profile"
    16  )
    17  
    18  // MemRepo is an in-memory implementation of the Repo interface
    19  type MemRepo struct {
    20  	*MemRefstore
    21  
    22  	bus        event.Bus
    23  	filesystem *muxfs.Mux
    24  	refCache   *MemRefstore
    25  	logbook    *logbook.Book
    26  	dscache    *dscache.Dscache
    27  
    28  	profiles profile.Store
    29  
    30  	doneWg  sync.WaitGroup
    31  	doneCh  chan struct{}
    32  	doneErr error
    33  }
    34  
    35  var _ Repo = (*MemRepo)(nil)
    36  
    37  // NewMemRepoWithProfile creates a new in-memory repository and an empty profile
    38  // store owned by the given profile
    39  func NewMemRepoWithProfile(ctx context.Context, owner *profile.Profile, fs *muxfs.Mux, bus event.Bus) (*MemRepo, error) {
    40  	keyStore, err := key.NewMemStore()
    41  	if err != nil {
    42  		return nil, err
    43  	}
    44  	pros, err := profile.NewMemStore(ctx, owner, keyStore)
    45  	if err != nil {
    46  		return nil, err
    47  	}
    48  	return NewMemRepo(ctx, fs, nil, nil, pros, bus)
    49  }
    50  
    51  // NewMemRepo creates a new in-memory repository
    52  func NewMemRepo(ctx context.Context, fs *muxfs.Mux, book *logbook.Book, cache *dscache.Dscache, pros profile.Store, bus event.Bus) (*MemRepo, error) {
    53  	var err error
    54  	if fs.Filesystem(qfs.MemFilestoreType) == nil {
    55  		err := fs.SetFilesystem(qfs.NewMemFS())
    56  		if err != nil {
    57  			return nil, err
    58  		}
    59  	}
    60  
    61  	p := pros.Owner(ctx)
    62  	if book == nil {
    63  		book, err = logbook.NewJournal(*p, bus, fs, "/mem/logbook.qfb")
    64  		if err != nil {
    65  			return nil, err
    66  		}
    67  	}
    68  
    69  	if cache == nil {
    70  		// NOTE: This dscache won't get change notifications from FSI, because it's not constructed
    71  		// with the hook for FSI.
    72  		cache = dscache.NewDscache(ctx, fs, bus, p.Peername, "")
    73  	}
    74  
    75  	mr := &MemRepo{
    76  		bus:         bus,
    77  		filesystem:  fs,
    78  		MemRefstore: &MemRefstore{},
    79  		refCache:    &MemRefstore{},
    80  		logbook:     book,
    81  		dscache:     cache,
    82  		profiles:    pros,
    83  
    84  		doneCh: make(chan struct{}),
    85  	}
    86  
    87  	mr.doneWg.Add(1)
    88  	go func() {
    89  		<-fs.Done()
    90  		mr.doneErr = fs.DoneErr()
    91  		mr.doneWg.Done()
    92  	}()
    93  
    94  	go func() {
    95  		mr.doneWg.Wait()
    96  		close(mr.doneCh)
    97  	}()
    98  
    99  	return mr, nil
   100  }
   101  
   102  // ResolveRef implements the dsref.Resolver interface
   103  func (r *MemRepo) ResolveRef(ctx context.Context, ref *dsref.Ref) (string, error) {
   104  	if r == nil {
   105  		return "", dsref.ErrRefNotFound
   106  	}
   107  
   108  	// TODO (b5) - not totally sure why, but memRepo doesn't seem to be wiring up
   109  	// dscache correctly in in tests
   110  	// if r.dscache != nil {
   111  	// 	return r.dscache.ResolveRef(ctx, ref)
   112  	// }
   113  
   114  	if r.logbook == nil {
   115  		return "", fmt.Errorf("cannot resolve local references without logbook")
   116  	}
   117  	return r.logbook.ResolveRef(ctx, ref)
   118  }
   119  
   120  // Bus accesses the repo's event bus
   121  func (r *MemRepo) Bus() event.Bus {
   122  	return r.bus
   123  }
   124  
   125  // Filesystem gives access to the underlying filesystem
   126  func (r *MemRepo) Filesystem() *muxfs.Mux {
   127  	return r.filesystem
   128  }
   129  
   130  // Logbook accesses the mem repo logbook
   131  func (r *MemRepo) Logbook() *logbook.Book {
   132  	return r.logbook
   133  }
   134  
   135  // Dscache returns a dscache
   136  func (r *MemRepo) Dscache() *dscache.Dscache {
   137  	return r.dscache
   138  }
   139  
   140  // RemoveLogbook drops a MemRepo's logbook pointer. MemRepo gets used in tests
   141  // a bunch, where logbook manipulation is helpful
   142  func (r *MemRepo) RemoveLogbook() {
   143  	r.logbook = nil
   144  }
   145  
   146  // SetLogbook assigns MemRepo's logbook. MemRepo gets used in tests a bunch,
   147  // where logbook manipulation is helpful
   148  func (r *MemRepo) SetLogbook(book *logbook.Book) {
   149  	r.logbook = book
   150  }
   151  
   152  // SetFilesystem implements QFSSetter, currently used during lib contstruction
   153  func (r *MemRepo) SetFilesystem(fs *muxfs.Mux) {
   154  	r.filesystem = fs
   155  }
   156  
   157  // RefCache gives access to the ephemeral Refstore
   158  func (r *MemRepo) RefCache() Refstore {
   159  	return r.refCache
   160  }
   161  
   162  // Profiles gives this repo's Peer interface implementation
   163  func (r *MemRepo) Profiles() profile.Store {
   164  	return r.profiles
   165  }
   166  
   167  // Done returns a channel that the repo will send on when the repo is closed
   168  func (r *MemRepo) Done() <-chan struct{} {
   169  	return r.doneCh
   170  }
   171  
   172  // DoneErr gives an error that occurred during the shutdown process
   173  func (r *MemRepo) DoneErr() error {
   174  	return r.doneErr
   175  }