@@ -13,7 +13,6 @@ import (
1313
1414 "github.com/ipfs/boxo/blockstore"
1515 "github.com/ipfs/boxo/exchange"
16- "github.com/ipfs/boxo/provider"
1716 "github.com/ipfs/boxo/verifcid"
1817 blocks "github.com/ipfs/go-block-format"
1918 "github.com/ipfs/go-cid"
@@ -74,21 +73,10 @@ type BoundedBlockService interface {
7473
7574var _ BoundedBlockService = (* blockService )(nil )
7675
77- // ProvidingBlockService is a Blockservice which provides new blocks to a provider.
78- type ProvidingBlockService interface {
79- BlockService
80-
81- // Provider can return nil, then no provider is used.
82- Provider () provider.Provider
83- }
84-
85- var _ ProvidingBlockService = (* blockService )(nil )
86-
8776type blockService struct {
8877 allowlist verifcid.Allowlist
8978 blockstore blockstore.Blockstore
9079 exchange exchange.Interface
91- provider provider.Provider
9280 // If checkFirst is true then first check that a block doesn't
9381 // already exist to avoid republishing the block on the exchange.
9482 checkFirst bool
@@ -111,13 +99,6 @@ func WithAllowlist(allowlist verifcid.Allowlist) Option {
11199 }
112100}
113101
114- // WithProvider allows to advertise anything that is added through the blockservice.
115- func WithProvider (prov provider.Provider ) Option {
116- return func (bs * blockService ) {
117- bs .provider = prov
118- }
119- }
120-
121102// New creates a BlockService with given datastore instance.
122103func New (bs blockstore.Blockstore , exchange exchange.Interface , opts ... Option ) BlockService {
123104 if exchange == nil {
@@ -140,11 +121,6 @@ func New(bs blockstore.Blockstore, exchange exchange.Interface, opts ...Option)
140121
141122// Blockstore returns the blockstore behind this blockservice.
142123func (s * blockService ) Blockstore () blockstore.Blockstore {
143- if s .provider != nil {
144- // FIXME: this is a hack remove once ipfs/boxo#567 is solved.
145- return providingBlockstore {s .blockstore , s .provider }
146- }
147-
148124 return s .blockstore
149125}
150126
@@ -157,13 +133,23 @@ func (s *blockService) Allowlist() verifcid.Allowlist {
157133 return s .allowlist
158134}
159135
160- func (s * blockService ) Provider () provider.Provider {
161- return s .provider
136+ // NewSession creates a new session that allows for
137+ // controlled exchange of wantlists to decrease the bandwidth overhead.
138+ // If the current exchange is a SessionExchange, a new exchange
139+ // session will be created. Otherwise, the current exchange will be used
140+ // directly.
141+ // Sessions are lazily setup, this is cheap.
142+ func NewSession (ctx context.Context , bs BlockService ) * Session {
143+ ses := grabSessionFromContext (ctx , bs )
144+ if ses != nil {
145+ return ses
146+ }
147+
148+ return newSession (ctx , bs )
162149}
163150
164- // NewSession creates a new session that allows for controlled exchange of
165- // wantlists to decrease the bandwidth overhead.
166- func NewSession (ctx context.Context , bs BlockService ) * Session {
151+ // newSession is like [NewSession] but it does not attempt to reuse session from the existing context.
152+ func newSession (ctx context.Context , bs BlockService ) * Session {
167153 return & Session {bs : bs , sesctx : ctx }
168154}
169155
@@ -183,7 +169,7 @@ func (s *blockService) AddBlock(ctx context.Context, o blocks.Block) error {
183169 }
184170 }
185171
186- if err = s .blockstore .Put (ctx , o ); err != nil {
172+ if err : = s .blockstore .Put (ctx , o ); err != nil {
187173 return err
188174 }
189175
@@ -194,11 +180,6 @@ func (s *blockService) AddBlock(ctx context.Context, o blocks.Block) error {
194180 logger .Errorf ("NotifyNewBlocks: %s" , err .Error ())
195181 }
196182 }
197- if s .provider != nil {
198- if err := s .provider .Provide (ctx , o .Cid (), true ); err != nil {
199- logger .Errorf ("Provide: %s" , err .Error ())
200- }
201- }
202183
203184 return nil
204185}
@@ -245,19 +226,16 @@ func (s *blockService) AddBlocks(ctx context.Context, bs []blocks.Block) error {
245226 logger .Errorf ("NotifyNewBlocks: %s" , err .Error ())
246227 }
247228 }
248- if s .provider != nil {
249- for _ , o := range toput {
250- if err := s .provider .Provide (ctx , o .Cid (), true ); err != nil {
251- logger .Errorf ("Provide: %s" , err .Error ())
252- }
253- }
254- }
255229 return nil
256230}
257231
258232// GetBlock retrieves a particular block from the service,
259233// Getting it from the datastore using the key (hash).
260234func (s * blockService ) GetBlock (ctx context.Context , c cid.Cid ) (blocks.Block , error ) {
235+ if ses := grabSessionFromContext (ctx , s ); ses != nil {
236+ return ses .GetBlock (ctx , c )
237+ }
238+
261239 ctx , span := internal .StartSpan (ctx , "blockService.GetBlock" , trace .WithAttributes (attribute .Stringer ("CID" , c )))
262240 defer span .End ()
263241
@@ -275,7 +253,7 @@ func getBlock(ctx context.Context, c cid.Cid, bs BlockService, fetchFactory func
275253 return nil , err
276254 }
277255
278- provider , blockstore := grabProviderAndBlockstoreFromBlockservice ( bs )
256+ blockstore := bs . Blockstore ( )
279257
280258 block , err := blockstore .Get (ctx , c )
281259 switch {
@@ -309,12 +287,6 @@ func getBlock(ctx context.Context, c cid.Cid, bs BlockService, fetchFactory func
309287 return nil , err
310288 }
311289 }
312- if provider != nil {
313- err = provider .Provide (ctx , blk .Cid (), true )
314- if err != nil {
315- return nil , err
316- }
317- }
318290 logger .Debugf ("BlockService.BlockFetched %s" , c )
319291 return blk , nil
320292}
@@ -323,6 +295,10 @@ func getBlock(ctx context.Context, c cid.Cid, bs BlockService, fetchFactory func
323295// the returned channel.
324296// NB: No guarantees are made about order.
325297func (s * blockService ) GetBlocks (ctx context.Context , ks []cid.Cid ) <- chan blocks.Block {
298+ if ses := grabSessionFromContext (ctx , s ); ses != nil {
299+ return ses .GetBlocks (ctx , ks )
300+ }
301+
326302 ctx , span := internal .StartSpan (ctx , "blockService.GetBlocks" )
327303 defer span .End ()
328304
@@ -360,7 +336,7 @@ func getBlocks(ctx context.Context, ks []cid.Cid, blockservice BlockService, fet
360336 ks = ks2
361337 }
362338
363- provider , bs := grabProviderAndBlockstoreFromBlockservice ( blockservice )
339+ bs := blockservice . Blockstore ( )
364340
365341 var misses []cid.Cid
366342 for _ , c := range ks {
@@ -419,14 +395,6 @@ func getBlocks(ctx context.Context, ks []cid.Cid, blockservice BlockService, fet
419395 cache [0 ] = nil // early gc
420396 }
421397
422- if provider != nil {
423- err = provider .Provide (ctx , b .Cid (), true )
424- if err != nil {
425- logger .Errorf ("could not tell the provider about new blocks: %s" , err )
426- return
427- }
428- }
429-
430398 select {
431399 case out <- b :
432400 case <- ctx .Done ():
@@ -506,21 +474,47 @@ func (s *Session) GetBlocks(ctx context.Context, ks []cid.Cid) <-chan blocks.Blo
506474
507475var _ BlockGetter = (* Session )(nil )
508476
477+ // ContextWithSession is a helper which creates a context with an embded session,
478+ // future calls to [BlockGetter.GetBlock], [BlockGetter.GetBlocks] and [NewSession] with the same [BlockService]
479+ // will be redirected to this same session instead.
480+ // Sessions are lazily setup, this is cheap.
481+ // It wont make a new session if one exists already in the context.
482+ func ContextWithSession (ctx context.Context , bs BlockService ) context.Context {
483+ if grabSessionFromContext (ctx , bs ) != nil {
484+ return ctx
485+ }
486+ return EmbedSessionInContext (ctx , newSession (ctx , bs ))
487+ }
488+
489+ // EmbedSessionInContext is like [ContextWithSession] but it allows to embed an existing session.
490+ func EmbedSessionInContext (ctx context.Context , ses * Session ) context.Context {
491+ // use ses.bs as a key, so if multiple blockservices use embeded sessions it gets dispatched to the matching blockservice.
492+ return context .WithValue (ctx , ses .bs , ses )
493+ }
494+
495+ // grabSessionFromContext returns nil if the session was not found
496+ // This is a private API on purposes, I dislike when consumers tradeoff compiletime typesafety with runtime typesafety,
497+ // if this API is public it is too easy to forget to pass a [BlockService] or [Session] object around in your app.
498+ // By having this private we allow consumers to follow the trace of where the blockservice is passed and used.
499+ func grabSessionFromContext (ctx context.Context , bs BlockService ) * Session {
500+ s := ctx .Value (bs )
501+ if s == nil {
502+ return nil
503+ }
504+
505+ ss , ok := s .(* Session )
506+ if ! ok {
507+ // idk what to do here, that kinda sucks, giveup
508+ return nil
509+ }
510+
511+ return ss
512+ }
513+
509514// grabAllowlistFromBlockservice never returns nil
510515func grabAllowlistFromBlockservice (bs BlockService ) verifcid.Allowlist {
511516 if bbs , ok := bs .(BoundedBlockService ); ok {
512517 return bbs .Allowlist ()
513518 }
514519 return verifcid .DefaultAllowlist
515520}
516-
517- // grabProviderAndBlockstoreFromBlockservice can return nil if no provider is used.
518- func grabProviderAndBlockstoreFromBlockservice (bs BlockService ) (provider.Provider , blockstore.Blockstore ) {
519- if bbs , ok := bs .(* blockService ); ok {
520- return bbs .provider , bbs .blockstore
521- }
522- if bbs , ok := bs .(ProvidingBlockService ); ok {
523- return bbs .Provider (), bbs .Blockstore ()
524- }
525- return nil , bs .Blockstore ()
526- }
0 commit comments