pipe-protocol
Version:
A protocol for large scale Interplanetary Intertool Agent Context
170 lines • 5.85 kB
JavaScript
"use strict";
/**
* @file IpfsNode Implementation
* @version 1.0.0
* @status STABLE - DO NOT MODIFY WITHOUT TESTS
* @lastModified 2024-02-03
*
* This file implements a unified IPFS node using Helia with configurable storage backends.
*
* IMPORTANT:
* - This is a STABLE implementation - any modifications require full test coverage
* - All changes must maintain backward compatibility
* - Changes affecting storage or networking require extensive testing
* - Run full test suite before and after modifications
* - Document all changes in the version history
*
* Core Functionality:
* - Configurable storage backend (memory or filesystem)
* - Network exposure control (enabled/disabled)
* - Data addition and retrieval with CID management
* - Explicit data export/import for private nodes
* - Node lifecycle management (init/cleanup)
* - Peer-to-peer communication (when networking enabled)
*
* Test Coverage Requirements:
* - Storage operations (add/get/delete)
* - Network isolation verification
* - Error handling and recovery
* - Resource cleanup
* - Cross-node communication
* - Data integrity verification
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.IpfsNode = void 0;
const helia_1 = require("helia");
const libp2p_1 = require("libp2p");
const libp2p_noise_1 = require("@chainsafe/libp2p-noise");
const libp2p_yamux_1 = require("@chainsafe/libp2p-yamux");
const tcp_1 = require("@libp2p/tcp");
const websockets_1 = require("@libp2p/websockets");
const blockstore_core_1 = require("blockstore-core");
const blockstore_fs_1 = require("blockstore-fs");
const identify_1 = require("@libp2p/identify");
const cid_1 = require("multiformats/cid");
const sha2_1 = require("multiformats/hashes/sha2");
const raw = require("multiformats/codecs/raw");
const multiaddr_1 = require("@multiformats/multiaddr");
class IpfsNode {
constructor(options) {
this.options = options;
this.helia = null;
this.blockstore = null;
this.libp2p = null;
}
async init() {
if (this.helia) {
return; // Already initialized
}
try {
const libp2p = await (0, libp2p_1.createLibp2p)({
addresses: {
listen: this.options.enableNetworking === false ? [] : ['/ip4/127.0.0.1/tcp/0']
},
transports: this.options.enableNetworking === false ? [] : [(0, tcp_1.tcp)(), (0, websockets_1.webSockets)()],
streamMuxers: [(0, libp2p_yamux_1.yamux)()],
connectionEncrypters: [(0, libp2p_noise_1.noise)()],
services: {
identify: (0, identify_1.identify)()
}
});
const blockstore = this.options.storage === 'memory'
? new blockstore_core_1.MemoryBlockstore()
: new blockstore_fs_1.FsBlockstore(this.options.storageConfig?.directory || '/tmp/ipfs');
this.blockstore = blockstore;
this.libp2p = libp2p;
this.helia = await (0, helia_1.createHelia)({
libp2p,
blockstore
});
}
catch (error) {
// Clean up any partially initialized resources
await this.stop();
throw error;
}
}
async add(data) {
if (!this.helia?.blockstore) {
throw new Error('IPFS node not initialized');
}
const hash = await sha2_1.sha256.digest(data);
const cid = cid_1.CID.createV1(raw.code, hash);
await this.helia.blockstore.put(cid, data);
await this.pin(cid.toString()); // Auto-pin content when adding
return cid.toString();
}
async put(data) {
return this.add(data);
}
async get(cidStr) {
if (!this.helia?.blockstore) {
throw new Error('IPFS node not initialized');
}
try {
const cid = cid_1.CID.parse(cidStr);
return await this.helia.blockstore.get(cid, { signal: AbortSignal.timeout(5000) });
}
catch (error) {
console.error('Error getting data:', error);
return null;
}
}
async pin(cidStr) {
if (!this.helia?.pins) {
throw new Error('IPFS node not initialized');
}
const cid = cid_1.CID.parse(cidStr);
await this.helia.pins.add(cid);
}
async unpin(cidStr) {
if (!this.helia?.pins) {
throw new Error('IPFS node not initialized');
}
const cid = cid_1.CID.parse(cidStr);
await this.helia.pins.rm(cid);
}
async getPinnedCids() {
if (!this.helia?.pins) {
throw new Error('IPFS node not initialized');
}
const pins = [];
for await (const pin of this.helia.pins.ls()) {
pins.push(pin.toString());
}
return pins;
}
getPeerId() {
return this.libp2p?.peerId ?? null;
}
getMultiaddrs() {
if (!this.libp2p) {
return [];
}
return this.libp2p.getMultiaddrs().map(addr => addr.toString());
}
async dial(addr) {
if (!this.libp2p) {
throw new Error('IPFS node not initialized');
}
await this.libp2p.dial((0, multiaddr_1.multiaddr)(addr));
}
async stop() {
if (this.helia) {
await this.helia.stop();
this.helia = null;
}
if (this.blockstore) {
if (this.options.storage === 'persistent') {
await this.blockstore.close();
}
this.blockstore = null;
}
if (this.libp2p) {
await this.libp2p.stop();
this.libp2p = null;
}
}
}
exports.IpfsNode = IpfsNode;
//# sourceMappingURL=ipfsNode.js.map