Initial implementation of path/resolver
This commit is contained in:
parent
8553fcf6c1
commit
a4b6a14ea5
2 changed files with 137 additions and 0 deletions
|
@ -35,4 +35,13 @@
|
|||
int ParseCidToPath (char *dst, char *txt);
|
||||
int ParsePath (char *dst, char *txt);
|
||||
int PathIsValid (char *p);
|
||||
|
||||
// Resolver provides path resolution to IPFS
|
||||
// It has a pointer to a DAGService, which is uses to resolve nodes.
|
||||
// TODO: now that this is more modular, try to unify this code with the
|
||||
// the resolvers in namesys
|
||||
typedef struct s_resolver {
|
||||
DAGService DAG;
|
||||
int (*ResolveOnce)(NodeLink **lnk, Context ctx, DAGService *ds, Node **nd, char *name);
|
||||
} Resolver;
|
||||
#endif // IPFS_PATH_H
|
||||
|
|
128
path/resolver.c
Normal file
128
path/resolver.c
Normal file
|
@ -0,0 +1,128 @@
|
|||
#include "ipfs/cid/cid.h"
|
||||
#include "ipfs/path/path.h"
|
||||
|
||||
Resolver* NewBasicResolver (DAGService *ds)
|
||||
{
|
||||
Resolver *ret = malloc(sizeof(Resolver));
|
||||
if (!ret) return NULL;
|
||||
ret->DAG = ds;
|
||||
ret->ResolveOnce = ResolveSingle;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// SplitAbsPath clean up and split fpath. It extracts the first component (which
|
||||
// must be a Multihash) and return it separately.
|
||||
int SplitAbsPath (struct Cid* cid, char ***parts, char *fpath)
|
||||
{
|
||||
*parts = Segments(fpath);
|
||||
|
||||
if (strcmp (**parts, "ipfs") == 0) *parts++;
|
||||
|
||||
// if nothing, bail.
|
||||
if (!**parts) return ErrNoComponents;
|
||||
|
||||
// first element in the path is a cid
|
||||
cid_decode_from_string(**parts, strlen(**parts), cid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ResolvePath fetches the node for given path. It returns the last item
|
||||
// returned by ResolvePathComponents.
|
||||
int ResolvePath(Node **nd, Context ctx, Resolver *s, char *fpath)
|
||||
{
|
||||
int err = IsValid(fpath);
|
||||
Node **ndd;
|
||||
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
err = ResolvePathComponents(&ndd, ctx, s, fpath);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
if (ndd == NULL) {
|
||||
return ErrBadPath;
|
||||
}
|
||||
while(*ndd) {
|
||||
*nd = *ndd;
|
||||
ndd++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ResolveSingle(NodeLink **lnk, Context ctx, DAGService *ds, Node **nd, char *name)
|
||||
{
|
||||
return ResolveLink(lnk, name);
|
||||
}
|
||||
|
||||
// ResolvePathComponents fetches the nodes for each segment of the given path.
|
||||
// It uses the first path component as a hash (key) of the first node, then
|
||||
// resolves all other components walking the links, with ResolveLinks.
|
||||
int ResolvePathComponents(Node ***nd, Context ctx, Resolver *s, char *fpath)
|
||||
{
|
||||
int err;
|
||||
struct Cid h;
|
||||
char **parts;
|
||||
|
||||
err = SplitAbsPath(&h, &parts, fpath);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
//log.Debug("resolve dag get");
|
||||
//*nd = s->DAG.Get(ctx, h);
|
||||
//if (nd == DAG_ERR_VAL) {
|
||||
// return DAG_ERR_VAL;
|
||||
//}
|
||||
|
||||
return ResolveLinks(ctx, *nd, parts);
|
||||
}
|
||||
|
||||
// ResolveLinks iteratively resolves names by walking the link hierarchy.
|
||||
// Every node is fetched from the DAGService, resolving the next name.
|
||||
// Returns the list of nodes forming the path, starting with ndd. This list is
|
||||
// guaranteed never to be empty.
|
||||
//
|
||||
// ResolveLinks(nd, []string{"foo", "bar", "baz"})
|
||||
// would retrieve "baz" in ("bar" in ("foo" in nd.Links).Links).Links
|
||||
int ResolveLinks(Node ***result, Context ctx, Node *ndd, char **names)
|
||||
{
|
||||
int err, idx = 0;
|
||||
NodeLink *lnk;
|
||||
Node *nd;
|
||||
|
||||
*result = calloc (sizeof(Node*), SegmentsLength(names) + 1);
|
||||
if (!*result) {
|
||||
return -1;
|
||||
}
|
||||
memset (*result, NULL, sizeof(Node*) * (SegmentsLength(names)+1));
|
||||
|
||||
*result[idx++] = ndd;
|
||||
nd = ndd; // dup arg workaround
|
||||
|
||||
while (*names) {
|
||||
//TODO
|
||||
//var cancel context.CancelFunc
|
||||
//ctx, cancel = context.WithTimeout(ctx, time.Minute)
|
||||
//defer cancel()
|
||||
|
||||
// for each of the path components
|
||||
err = ResolveLink(&lnk, *names);
|
||||
if (err) {
|
||||
char msg[51];
|
||||
*result[idx] = NULL;
|
||||
snprintf(msg, sizeof(msg), ErrPath[ErrNoLinkFmt], *names, nd->Cid);
|
||||
if (ErrPath[ErrNoLink]) {
|
||||
free(ErrPath[ErrNoLink]);
|
||||
}
|
||||
ErrPath[ErrNoLink] = malloc(strlen(msg) + 1);
|
||||
if (ErrPath[ErrNoLink]) {
|
||||
strcpy(ErrPath[ErrNoLink], msg);
|
||||
}
|
||||
free (*result);
|
||||
return ErrNoLink;
|
||||
}
|
||||
names++;
|
||||
}
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue