Skip to content
This repository has been archived by the owner on Feb 12, 2024. It is now read-only.

chore: make IPFS API static (remove api-manager) #3365

Merged
merged 34 commits into from
Dec 4, 2020

Conversation

Gozala
Copy link
Contributor

@Gozala Gozala commented Oct 31, 2020

This pull request changes of how things are wired internally, to make it simpler and cleaner. Below is the high level overview of the changes:

  • api-manager is gone.
  • There is now Storage component that is glorified {keychain, repo, peerId} tuple, that one can async start and it takes care of repo bootstrapping (which init used to do). As per discussion with @achingbrain init was mostly there for historical reasons.
  • There is now Network service component that is glorified {peerId, libp2p, bitswap} tuple.
    • All components that depended upon libp2p or peerId depend on network service now.
    • They can do await network.use(options) and get tuple when node is started (if it is starting or started) or an exception if start has not been initiated.
    • This way IPFS node is no longer mutated and APIs that depend on node been started throw if called before start.
  • lot of TS typings were added to be able to make this changes with more confidence.
  • Set of interfaces were added for things like datastore, repo, bitswap
    • create can be passed implementations and it's useful to decouple interface from a concrete implementation.
    • We had no types for those and it helped having interfaces to increase coverage and enable making these changes.

      I would like to migrate those to other repos, but doing it as would be more effective than having to coordinate changes across many repos.

  • circular dependencies between pinmanager and dag APIs are resolved.

@achingbrain @vasco-santos please be vigorous. Tests end up catching more bugs than I could have anticipated & I'm bit afraid there might be some that slipped.

Copy link
Member

@vasco-santos vasco-santos left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the network stand point this looks good to me. I couldn't do an exhaustive review atm as this was quite big. Good work with all the types, I definitely need to do the same for libp2p.

Just left some minor observations I found and I will leave a more design heathy review for @achingbrain

packages/ipfs-core/src/components/block/get.js Outdated Show resolved Hide resolved
packages/ipfs-core/src/components/config.js Outdated Show resolved Hide resolved
@hugomrdias hugomrdias self-requested a review November 10, 2020 09:28
Copy link
Member

@hugomrdias hugomrdias left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

partial review, do you think writing the config typedef would be to hard ?

packages/ipfs-cli/src/commands/init.js Show resolved Hide resolved
packages/ipfs-core/src/components/block/rm.js Show resolved Hide resolved
config.Bootstrap.push(multiaddr.toString())
}

await repo.config.set(config)
await repo.config.replace(config)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why the change from set to replace ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because interface of set is set(path,:string value:any) and replace has replace(value:Config). Later can ensure that what you pass is what's expected former can not. I also did not wanted to do the set overload typing because they tend to have issues.

packages/ipfs-core/src/components/dag/get.js Outdated Show resolved Hide resolved
Copy link
Member

@achingbrain achingbrain left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I appreciate that a change like this will touch a lot of files but if we are to merge changes like this in a timely fashion it's vitally important to restrict the scope of the work being done.

There seem to be a lot of internal refactors here that could have been done as separate PRs which would reduce the cognitive load on the reviewers and also give everyone involved a bit more confidence that the changes do not introduce regressions in poorly tested areas of the codebase.

docs/core-api/BITSWAP.md Outdated Show resolved Hide resolved
packages/interface-ipfs-core/src/add.js Outdated Show resolved Hide resolved
@@ -59,13 +59,11 @@ module.exports = ({ bitswap }) => {
* @typedef {object} BitswapStats - An object that contains information about the bitswap agent
* @property {number} provideBufLen - an integer
* @property {CID[]} wantlist
* @property {string[]} peers - array of peer IDs as Strings
* @property {CID[]} peers - array of peer IDs
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See docs comment, peer IDs should be strings consistent with ipfs.swarm.peers

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current implementation is not and docs / types were incorrect. And I have submitted #3389 to address that separately.

packages/ipfs-core/src/components/block/get.js Outdated Show resolved Hide resolved
@@ -0,0 +1,28 @@
import CID from 'cids'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are there .ts files being added? The agreed approach for this project is to generate types from JSDoc comments.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we talked about it. This are interface definitions for things we claim users can provide own implementations for. I think it would make sense to migrate some e.g. to https://github.com/ipfs/interface-datastore/ and others might need a new home. However it made most sense to me to put them here first and migrate them elsewhere afterwards.

This makes it possible to specify what interface option like bitswap, blockService, ipld, repo etc have to implement to qualify. Furthermore this dramatically increased type coverage. I think what we'd need to do in ipfs-bitswap, ipfs-block-service etc... is say that they @implements {BitSwap} etc... That way

  1. We code against the interface not against our own implementation. We already use some internal properties that aren't part of the interface which implies that interface we have has gaps and we should probably rethink interface.

  2. Other implementations could be coded against interface and @implements {X} will enforce compatibility, as opposed to doing it against markdown documents that are (, as it turns out) out of sync.

So I don't think it's an alternative to generating types from code. It's complementary and forces us to uphold interface contract we our selfs defined.

/**
* @private
* @param {Service<any, any>} service
* @returns {never}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be @returns {void}? Then apparently we don't need the eslint-disable-next-line - https://eslint.org/docs/rules/valid-jsdoc

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No it needs to be never because it can never return and by consequence can be used e.g. to here:

const div = (a:number, b:number) : number => {
  if (b === 0) return panic() // never
  return a / b
}

Note that if panic returned void type checker would complain that return type is number|void and not a number. Whilenever|number is equivalent of number.

Here specifically it used in switch statements

packages/ipfs-core/src/utils/service.js Outdated Show resolved Hide resolved
packages/ipfs-core/src/utils/service.js Outdated Show resolved Hide resolved
packages/ipfs-core/src/utils/service.js Outdated Show resolved Hide resolved
@Gozala Gozala mentioned this pull request Nov 12, 2020
packages/ipfs-core/src/components/dag/index.js Outdated Show resolved Hide resolved
@@ -35,6 +35,7 @@ module.exports = ({ gcLock, pin, refs, repo }) => {
// Mark all blocks that are being used
const markedSet = await createMarkedSet({ pin, refs, repo })
// Get all blocks keys from the blockstore
// @ts-ignore - TS is not aware of keysOnly overload
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have an issue for this ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is this thread ipfs/interface-datastore#38 and as I mentioned somewhere here I do intend to trickle down interface defs introduces here to various packages as followup work, which I hope will be a driving force to rethink some of the API choices made.

For this specifically it seems like having a separate query method would be simple and pragmatic solution, that does not require some advanced type magic that I'm trying to reduce as much as possible.

Comment on lines +16 to +18
this.gc = createGC({ gcLock, pin, refs, repo })
this.stat = createStat({ repo })
this.version = createVersion({ repo })
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe we should inline the code for these in this file reducing the boilerplate, could be done for other API classes also.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understand what you mean, could you please elaborate ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now that we have the wrapper classes maybe we dont need one file per function everywhere and could inline those functions inside the wrapper class file reducing the types boilerplate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't mind that, but would rather pursue as separate endeavour if we decide to do it.

@hugomrdias
Copy link
Member

im good with discussing this in the other issue.

I think we are saying the some thing, just by different words.

  • Moving UnixFSEntry to ipfs-unixfs

We should not block this PR because of this. Just create an issue to follow up.

  • Should this PR cange repo.config.set(config) to repo.config.replace(config) ?

Im good with this change.

Im good with these, just think we should has a general rule try to make types simpler even if that makes us write more characters.

@Gozala
Copy link
Contributor Author

Gozala commented Nov 16, 2020

We should not block this PR because of this. Just create an issue to follow up.

ipfs/js-ipfs-unixfs#94

@achingbrain achingbrain changed the title Make IPFS API static (remove api-manager) chore: make IPFS API static (remove api-manager) Nov 20, 2020
@achingbrain
Copy link
Member

@Gozala can you please resolve the conflicts on this PR?

@Gozala
Copy link
Contributor Author

Gozala commented Nov 23, 2020

@Gozala can you please resolve the conflicts on this PR?

@achingbrain I would much rather do it after I've got tentative 👍, because each takes I had to do it it took significant effort as I basically need to discard all changes to init.js and start.js, stop.js etc... and then manually reapply changes that had occurred there (had to do couple times already) .

So if it is not too much to ask, I would very much prefer to get this PR to the point where it looks good and then get it up to date once instead of every time something is pushed to master. If this sounds unreasonable, I'll do what you asked.

@hugomrdias
Copy link
Member

you got my 👍🏼 to rebase and get this merged ASAP

@achingbrain
Copy link
Member

@Gozala you have a tentative 👍, please resolve the conflicts on this PR to stop it becoming stale.

@Gozala
Copy link
Contributor Author

Gozala commented Nov 25, 2020

@hugomrdias could you please release ipfsd-ctl that includes the changes from ipfs/js-ipfsd-ctl#560 because now npm install fails now as branch got deleted. I can update to master, but since I'd need to update once again to remove git urls, I'd much rather do it once

@Gozala
Copy link
Contributor Author

Gozala commented Nov 26, 2020

@achingbrain @hugomrdias I have merged in all the upstream changes & fixed all the new errors that type-checker has discovered now that previously untyped dependencies (like Block) gained typings.

In the process I also discovered problem with withTimoutOptions which caused it's returned function to be inferred as any. I have also cherry-picked fix for that into separate PR #3422

I have not got around to updating all the import paths which I said I would. But if you two are ok with doing it as followup PR, I could just refactor all of the typings as per #3413

@hugomrdias
Copy link
Member

I have not got around to updating all the import paths which I said I would. But if you two are ok with doing it as followup PR, I could just refactor all of the typings as per #3413

👍🏼

@achingbrain achingbrain merged commit c3c4607 into master Dec 4, 2020
@achingbrain achingbrain deleted the chore/kill-api-manager branch December 4, 2020 18:22
@achingbrain
Copy link
Member

@Gozala can you please create issues for all the follow-up work that needs to be done

SgtPooki referenced this pull request in ipfs/js-kubo-rpc-client Aug 18, 2022
- api-manager is gone.
- There is now Storage component that is glorified `{keychain, repo, peerId}` tuple, that one can `async start` and it takes care of repo bootstrapping (which `init` used to do). As per discussion with @achingbrain `init` was mostly there for historical reasons.
- There is now `Network` service component that is glorified `{peerId, libp2p, bitswap}` tuple.
   - All components that depended upon `libp2p` or `peerId` depend on `network` service now.
   - They can do `await network.use(options)` and get tuple when node is started (if it is starting or started) or an exception if start has not been initiated.
   - This way IPFS node is no longer mutated and APIs that depend on node been started throw if called before start.
- lot of TS typings were added to be able to make this changes with more confidence.
- Set of interfaces were added for things like datastore, repo, bitswap
   - create can be passed implementations and it's useful to decouple interface from a concrete implementation.
   - We had no types for those and it helped having interfaces to increase coverage and enable making these changes.
      > I would like to migrate those to other repos, but doing it as would be more effective than having to coordinate changes across many repos.
- circular dependencies between pinmanager and dag APIs are resolved.

Co-authored-by: Alex Potsides <alex@achingbrain.net>
Co-authored-by: Hugo Dias <hugomrdias@gmail.com>
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants