JavaScript OS에 IPFS 추가

나는 한동안 Web 3.0 구절에 발을 담그고 싶었습니다. 특히 내 사이드 ​​프로젝트인 a Desktop environment in the browser ( daedalOS )에 통합되었습니다.

첫 번째 단계로 ipfs native url 지원을 추가하기로 결정했습니다. 이 지원을 Browser ( Demo ), Run Dialog , Shortcuts & Terminal 에 추가했습니다. 대부분의 주요 ipfs 기능을 마이그레이션했습니다utils/ipfs.ts.



이것이 작동하는 방식에 대한 기본 개념은 ipfs 기본 URL을 가져 와서 ipfs gateway을 사용하는 URL로 변환하는 것입니다. 제 경우에는 official ipfs gateways을 폴백으로 추가하고 Cloudflare gateways을 기본으로 추가했습니다.

const IPFS_GATEWAY_URLS = [
  "https://<CID>.ipfs.cf-ipfs.com/",
  "https://<CID>.ipfs.dweb.link/",
  "https://cloudflare-ipfs.com/ipfs/<CID>/",
  "https://gateway.ipfs.io/ipfs/<CID>/",
];


URL을 만들 때 CORS 친화적이지 않은 CID v0과 혼동하지 않도록 최신CID v1 format을 사용하려고 합니다. 대소문자를 구분하지 않는 base32 형식을 사용하는 이 형식으로 변환하기 위해 라이브러리multiformats를 사용했습니다.

let IPFS_GATEWAY_URL = "";

const getIpfsGatewayUrl = async (
  ipfsUrl: string,
  notCurrent?: boolean
): Promise<string> => {
  if (!IPFS_GATEWAY_URL || notCurrent) {
    const urlList = notCurrent
      ? IPFS_GATEWAY_URLS.filter((url) => url !== IPFS_GATEWAY_URL)
      : IPFS_GATEWAY_URLS;

    for (const url of urlList) {
      if (await isIpfsGatewayAvailable(url)) {
        IPFS_GATEWAY_URL = url;
        break;
      }
    }

    if (!IPFS_GATEWAY_URL) return "";
  }

  const { pathname, protocol, search } = new URL(ipfsUrl);

  if (protocol !== "ipfs:") return "";

  const [cid = "", ...path] = pathname.split("/").filter(Boolean);
  const { CID } = await import("multiformats/cid");

  return `${IPFS_GATEWAY_URL.replace(
    "<CID>",
    CID.parse(cid).toV1().toString()
  )}${path.join("/")}${search}`;
};




사용할 게이트웨이를 찾기 위해 초기 검사를 수행할 때 가용성 검사기를 public-gateway-checker에서 가져온 코드에 기반했습니다.

const isIpfsGatewayAvailable = (gatewayUrl: string): Promise<boolean> =>
  new Promise((resolve) => {
    const timeoutId = window.setTimeout(
      () => resolve(false),
      1000
    );
    const img = new Image();

    img.addEventListener("load", () => {
      window.clearTimeout(timeoutId);
      resolve(true);
    });
    img.addEventListener("error", () => {
      window.clearTimeout(timeoutId);
      resolve(false);
    });

    img.src = `${gatewayUrl.replace(
      "<CID>",
      // https://github.com/ipfs/public-gateway-checker/blob/master/src/constants.ts
      "bafybeibwzifw52ttrkqlikfzext5akxu7lz4xiwjgwzmqcpdzmp3n5vnbe"
    )}?now=${Date.now()}&filename=1x1.png#x-ipfs-companion-no-redirect`;
  });


실제로 요청을 수행할 때 새 ipfs 게이트웨이 URL에 필요한 것은 일반fetch() 명령뿐입니다.

const getIpfsResource = async (ipfsUrl: string): Promise<Buffer> => {
  let response: Response | null = null;
  const requestOptions = {
    cache: "no-cache",
    credentials: "omit",
    keepalive: false,
    mode: "cors",
    priority: "high",
    referrerPolicy: "no-referrer",
    window: null,
  } as RequestInit;

  try {
    response = await fetch(await getIpfsGatewayUrl(ipfsUrl), requestOptions);
  } catch (error) {
    if ((error as Error).message === "Failed to fetch") {
      response = await fetch(
        await getIpfsGatewayUrl(ipfsUrl, true),
        requestOptions
      );
    }
  }

  return response instanceof Response
    ? Buffer.from(await response.arrayBuffer())
    : Buffer.from("");
};




또한 올바른 앱에서 URL을 열려고 시도할 수 있도록 파일 유형 감지를 추가했습니다. 이것은 라이브러리file-type를 사용하여 수행됩니다.

const getIpfsFileName = async (
  ipfsUrl: string,
  ipfsData: Buffer
): Promise<string> => {
  const { pathname, searchParams } = new URL(ipfsUrl);
  const fileName = searchParams.get("filename");

  if (fileName) return fileName;

  const { fileTypeFromBuffer } = await import("file-type");
  const { ext = "" } = (await fileTypeFromBuffer(ipfsData)) || {};

  return `${pathname.split("/").filter(Boolean).join("_")}${
    ext ? `.${ext}` : ""
  }`;
};


나는 게이트웨이의 신뢰성이 꽤 좋다는 것을 알았지만 때때로 요청이 시작되기 전에 많은 양의 지연이 있었습니다.

내 기사를 읽어 주셔서 감사합니다. 내 개인 웹사이트이기도 한 daedalOSdustinbrett.com에서 일부 ipfs URL을 사용해 보십시오.

이 모든 ipfs 마법의 클라이언트인 daedalOS에 대해 더 알고 싶다면 ipfs를 포함한 다양한 기능을 살펴보는 제 비디오를 확인하십시오. 감사!

좋은 웹페이지 즐겨찾기