Configurable Multiplexed Filesystem
b5 opened this issue · 8 comments
RFC 0029 requires changes to qfs
to make it configurable. Using some combination of qri
and qfs
, we need a function that returns a qfs.Filesystem
implementation from configuration data that looks like this:
Filesystems:
- type: ipfs
options:
path: ~/.ipfs
api: true
pubsub: false
- type: local
- type: http
One of the big questions is which of qri-io/config
and qfs
should do which parts of parsing, but before we get to that question, we know a few things:
- The returned
Filesystem
will be aMux
filesystem, because it composes one or more Filesystems - anything that processes this configuration input will need to import all the various possible implementations, so config processing can't be defined in the base
qfs
package, because it's an "interface declaration package" - We have strong patterns for
New
functions that accept "Options" for configuration, like lib.NewInstance
Based on all that I think the right answer is to **move qfs.Mux
into a new muxfs
sub-package (github.com/qri-io/qfs/muxfs), and use the muxifs.New
as the place where all this configuration happens. We should also be working to make sure every other package's configuration declaration is uniform, and can accept a map[string[interface{}
set of configuration options that will be passed down from the higher configuration file. muxfs.New
can do the routing to different filesystem implementations by switching on the provided type
field.
Originally going to file this issue in qri
, but since it only references qri/repo/buildrepo
code but is implemented here, I think it makes more sense to expand on this issue.
From qri/repo/buildrepo
:
We expect local
, http
, cafs
, and ipfs
as options.
And from the same buildrepo
file, a NewCAFSStore
(which is stored in the mux fs under cafs
) can be a ipfs
, a ipfs_http
, or a map
.
My initial draft of muxfs.New
doesn't make sense now that I understand better how it's used and what the fields are supposed to be.
mux fs fields:
ipfs
- (qipfs.Filestore
)
local
- (localfs.Filestore
)
http
- (httpfs.Filestore
)
cafs
- any cafs.Filestore
(possibilities are ipfs
, ipfs_http
, or map
)
In buildrepo.NewFilesystem
, we take a passed in store
and use the store in place of the cafs
filesystem in the returned mux. Is this the paradigm we should we working toward? Or will we build the cafs
filesystem in our qfs.New
and pull the store from the muxfs
? Basically, should this qfs.New
be expected to create the store itself?
If an ipfs
config is passed in, should we assume this will fill the cafs
and the ipfs
slots? Or should there be a separate cafs
section in the config?
Okay after chat with @b5 here is the game plan.
We really do want each type of filesystem to have its own field in a MuxFS
, rather than obfuscating mem
, ipfs
(sometimes), and ipfs_http
underneath cafs
. "cafs" is a characteristic a filesystem can have, and one muxfs
can have multiple stores that each are content addressed. We also need to update the way that qfs determines which filesystem a path
is trying to access.
To that effect, muxfs.New
will switch on:
ipfs
local
http
ipfs_http
mem
However, we will also need to update the qfs.PathKind
function to use path prefixes to determine which of those filesystems is trying to be accessed.
Thinking about defaults:
- If a MuxConfig just has a
Type
, filed out but noConfig
associated with thatType
, each subpackage should use aDefaultConfig
- We need a
muxfs.OptISetPFSPath
that takes a string. If it's empty, we should try to either get the ipfs path relative to the QRI_PATH and set theMuxConfig
for theqipfs.Filesystem
accordingly.
@b5 running into a little bit of a logic snag, and want to run my thoughts by you
I'm understanding more why we had one "cafs" section to obscure ipfs
and ipfs_http
.
Both ipfs
and ipfs_http
filesystems use the ipfs
prefix. So any PathKind
function will always return "ipfs" as the type, and ipfs_http would never be called.
-
Do we want users to be able to set up both an ipfs and ipfs_http options? If not, I'm proposing we figure this out during config: you can only have one
ipfs
option, but if you only have aipfsApiUrl
field in the config, we actually set up anipfs_http
fs rather than a typicalipfs
fs. -
If we want users to be able to set up both... how do we differentiate? One option is to expect hashes prefixed by
ipfs_http
to resolve viaipfs_http
, and we do the hash/path adjustment inipfs_http
. However, I'm not sure if it is reasonable to expect aipfs_http
prefix as I'm not sure what context this would get used in.
Your hunch is right. The http implementation of the Ipfs filestore should be a configurable fallback. Users shouldn’t be able to declare a file system config type ipfs_http
.
we'll need some sort of apiAddr
config key that wants a multi address value on the ipfs
filesystem type. ipfs_http
configuration should be sensitive to this. The ipfs
filesystem initializer should fall back to trying to connect over this address if it cannot obtain the repo lock and the value is populated.
To clarify, this "falling back" should happen in the cafs/ipfs.New
function? If we can't create an ipfs
fs, we should instead (inside the qipfs.New
func) call cafs/ipfs_http.New
and pass in a ipfs_http
fs (if the apiAddr
field is populated)
Yes exactly