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 }