How to use ipfs.create() - for beginners

I’m using TypeScript, for a browser app, and I’m just trying to get the basics working now that I have completed a few ProtoSchool tutorials. I have noticed that it’s either impossible or impractical to use IPFS as per its documentation if using TypeScript as opposed to its JavaScript documentation, which uses create as a top level await:

const ipfs = await IPFS.create();

So I created a workaround/hack:

interface IpfsCreateMemo {
    [key: string]: any;
}

const ipfsCreateMemo: IpfsCreateMemo = {};

async function createIpfs(props?: object) {
    const memo: string = props ? Object.entries(props).join(',') : 'null';

    if (memo in ipfsCreateMemo === false) {
        ipfsCreateMemo[memo] = await IPFS.create(props);
    }

    return ipfsCreateMemo[memo];
}

This ‘works’, unless I call on this method quickly in my app. If I quickly call it I will get an error: LockExistsError: Lock already being held for file: ipfs/repo.lock.

So my questions surround this basic issue of using ipfs.create reliably despite using TypeScript. How can I avoid this error? Should I just work around this error? Where can I find the documentation for all ipfs commands, particularly the create method?

I know where the core commands’ documentation are (new users are not allowed links, sorry). I notice many links to read “the docs” or “documentation” which only reference pages where readers are admonished to read “the docs” or “documentation” in some infinitely recursive manner.

Although not directly related to my question, I’m humbly suggesting more detailed link text than “documentation” or “the docs” and perhaps given the complexity of this project and related dependencies, a documentation directory with search capabilities functioning like a table of contents and index may be in order. I think I know where the master documentation page for the JavaScript API, but I can find it neither directly from docs.ipfs.io nor subpages. Maybe I didn’t try hard enough, maybe ipfs.create() is actually pseudo code. Either way I have no idea how I can find documentation for the create method without getting lucky on Google (so far no luck), but I know it seems to be essential to many other commands based on example documentation.

You probably want to be returning a promise from your async function. Remember, it will return immediately well before any of the stuff has completed in it. Here’s some examples what that looks like:

when you see the docs like on this page: https://js.ipfs.io/, that example code is assuming it’s already inside some async function that will return a promise or else they wouldn’t be starting with just an await even on the very first line.

Here is my async function that calls createIpfs:

export async function getLatest() {
    try {
        const ipfs = await createIpfs();

        for await (const ref of ipfs.refs.local()) {
            if (ref.err) {
                console.error(ref.err)
            } else {
                console.log(ref.ref)
            }
        }

        return ipfs.refs.local();
    } catch (e) {
        console.error('Errorish: ', e);
    }
}

If I call getLatest quickly on opening the web app const ipfs = await createIpfs(); will throw an error: LockExistsError: Lock already being held for file: ipfs/repo.lock. I don’t understand how refactoring the code as a series of promises will solve a problem that async/await isn’t already solving. This error also happens from calling this code await IPFS.create(); more than once which is not discussed in the example code you cited. So, if I put the code, await IPFS.create();, in the function, getLatest, in place of createIpfs, I get that error: LockExistsError: Lock already being held for file: ipfs/repo.lock.`

More than any other concern I have, I would be happy to know just how exactly the code in the example, https://js.ipfs.io/, specifically const node = await IPFS.create(), is called more than once without error or if it means to be handled another way despite not showing that method.

I made some code that will always predictably fail:

export async function getLatest() {
        const ipfs = await IPFS.create(); //        const ipfs = await createIpfs();

        try {
            const node = await IPFS.create();
        } catch (e) {
            console.error('This is the problem--the code cannot be called more than once: ', e);
        }

        for await (const ref of ipfs.refs.local()) {
            if (ref.err) {
                console.error(ref.err)
            } else {
                console.log(ref.ref)
            }
        }

        return ipfs.refs.local();
}

If you take out the try/catch block but run the function twice the same error happens. Does that at least clarify what the problem is?

I read somewhere that’s true I think, that you can’t initialize that more than once. That’s probably all you need to change? Only call once.

BTW: I had never realized (until today) that you can just return a value from an ‘async’ function and TypeScript automatically wraps that value in an already-resolved promise. So what I originally said about you needing to return a Promise was wrong. My apologies. I found out I have 44 of my own functions I can make cleaner based on learning that. So you were the one who helped me it seems. :slight_smile:

2 Likes

I finally found the documentation for the create method.