Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Customize the fallback order of IPFS providers #3

Closed
lidel opened this issue Jun 11, 2019 · 8 comments · Fixed by #17
Closed

Customize the fallback order of IPFS providers #3

lidel opened this issue Jun 11, 2019 · 8 comments · Fixed by #17

Comments

@lidel
Copy link
Member

lidel commented Jun 11, 2019

There should be a way to customize the order in which providers are tried.
For example, if I want to ensure my app tries remote API before falling back to window.ipfs and embedded js-ipfs, I should be able to specify providers via ordered list:

const { ipfs, provider } = await getIpfs({
  fallbackOrder: ['api','window.ipfs', 'js-ipfs']  // strings? import enums?
  apiAddress:    '/ip4/10.1.1.1/tcp/5002'
  jsIpfsOpts:    {}
})

Additional notes:

  • Providing ordered list of providers should take precedence over individual flags such as tryApi: false
  • cc @parkan for thoughts and suggestions for use cases at Internet Archive
@parkan
Copy link

parkan commented Aug 12, 2019

hi, sorry this slipped past me back in June

thoughts:

  • having multiple control mechanisms for whether providers should be tried and in what order is difficult to reason about (would need to read docs to understand inclusion in fallbackOrder takes precedence over tryThing, for ex.)

    using fallbackOrder alone (with a healthy default) is sufficient to signify both, though (1) you need a way to enumerate legal values to know what to put in there (2) any new providers added in an update would not be enabled if you have a custom fallbackOrder set (though maybe that’s for the best)

  • another way could be to use a Map that signifies order (key order) and enabled/disabled state (bool values), though of course we still don’t have a nice looking Map literal syntax 😢

  • re: IA, it’s probably best to sync up with Mitra as to their current thinking

@lidel
Copy link
Member Author

lidel commented Aug 14, 2019

Idea: providers – a predefined Map of Symbols:

import { getIpfs, providers } from 'ipfs-provider'
const { httpClient, windowIpfs, jsIpfs } = providers
const { ipfs, provider } = await getIpfs({
  fallbackOrder: [ httpClient, windowIpfs, jsIpfs ]
  apiAddress:    '/ip4/10.1.1.1/tcp/5002'
  jsIpfsOpts:    {}
})

@parkan
Copy link

parkan commented Aug 15, 2019

what are the value in this example?

@lidel
Copy link
Member Author

lidel commented Aug 19, 2019

I was thinking along these lines:

const providers = Object.freeze({ 
  httpClient: Symbol('httpClient')
  windowIpfs: Symbol('windowIpfs')
  jsIpfs: Symbol('jsIpfs')
})

cc @hugomrdias if there is a better/more intuitive way to do this

@hugomrdias
Copy link
Member

// providers.js

export {
	httpClient : (options = {}) => { 
		options = mergeOptions(defaults, options)
		return 'everything needed'
	},
	windowIpfs : (options = {}) => { 
		options = mergeOptions(defaults, options)
		return 'everything needed'
	},
	jsIpfs : (options = {}) => { 
		options = mergeOptions(defaults, options)
		return 'everything needed'
	},
}
import { getIpfs, providers } from 'ipfs-provider'
const { httpClient, windowIpfs, jsIpfs } = providers
const { ipfs, provider } = await getIpfs([ 
	httpClient({apiAddress: '/ip4/10.1.1.1/tcp/5002'}), 
	windowIpfs(), 
	jsIpfs({})
])

i would do it like this

@parkan
Copy link

parkan commented Aug 27, 2019

@hugomrdias that looks good, one concern is that even though the provider-specific options are better encapsulated this way, we may still have some global options, so I’d pass the array as a named parameter to the constructor

another comment would be that the provider constructors here need to be lazy: don’t want to start up all the nodes before picking one to actually use

@lidel
Copy link
Member Author

lidel commented Aug 28, 2019

Below should address:

  • lazy constructors
  • support global options
// providers.js

export {
	httpClient : (options = {}) => { 
		options = mergeOptions(defaults, options)
		return () => 'everything needed'
	},
	windowIpfs : (options = {}) => { 
		options = mergeOptions(defaults, options)
		return () => 'everything needed'
	},
	jsIpfs : (options = {}) => { 
		options = mergeOptions(defaults, options)
		return () => 'everything needed'
	},
}
// sample use

import { getIpfs, providers } from 'ipfs-provider'
const { httpClient, windowIpfs, jsIpfs } = providers
const { ipfs, provider } = await getIpfs({
	providers: [ 
		httpClient({ apiAddress: '/ip4/10.1.1.1/tcp/5002' }), 
		windowIpfs({ commands: ['add','cat'] }), 
		jsIpfs({
			getJsIpfs: () => import('ipfs'),
			jsIpfsOpts: { /* advanced config */ }
		})
	],
    someGlobalOption: 'some value'
})

Y/n? Anything missing?

@parkan
Copy link

parkan commented Aug 30, 2019

lgtm!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants