const axios = require('axios');
const FormData = require('form-data');
const fs = require('fs');
const { tableFromIPC } = require('apache-arrow');
const WebSocket = require('ws');
class IPFRSClient {
constructor(baseUrl = 'http://localhost:8080') {
this.baseUrl = baseUrl.replace(/\/$/, '');
this.client = axios.create({
baseURL: this.baseUrl,
timeout: 30000,
});
}
async addFile(filePath) {
const form = new FormData();
form.append('file', fs.createReadStream(filePath));
const response = await this.client.post('/api/v0/add', form, {
headers: form.getHeaders(),
});
return response.data;
}
async cat(cid) {
const response = await this.client.post(`/api/v0/cat?arg=${cid}`, null, {
responseType: 'arraybuffer',
});
return Buffer.from(response.data);
}
async getBlock(cid) {
const response = await this.client.post(`/api/v0/block/get?arg=${cid}`, null, {
responseType: 'arraybuffer',
});
return Buffer.from(response.data);
}
async putBlock(data) {
const form = new FormData();
form.append('block', data);
const response = await this.client.post('/api/v0/block/put', form, {
headers: form.getHeaders(),
});
return response.data;
}
async get(cid, byteRange = null) {
const headers = {};
if (byteRange) {
const [start, end] = byteRange;
headers['Range'] = `bytes=${start}-${end}`;
}
const response = await this.client.get(`/ipfs/${cid}`, {
headers,
responseType: 'arraybuffer',
});
return Buffer.from(response.data);
}
async batchGetBlocks(cids) {
const response = await this.client.post('/v1/block/batch/get', { cids });
return response.data.blocks;
}
async batchHasBlocks(cids) {
const response = await this.client.post('/v1/block/batch/has', { cids });
return response.data.results;
}
async streamingUpload(filePath) {
const form = new FormData();
form.append('file', fs.createReadStream(filePath));
const response = await this.client.post('/v1/stream/upload', form, {
headers: form.getHeaders(),
});
return response.data;
}
async streamingDownload(cid, chunkSize = 65536) {
const response = await this.client.get(`/v1/stream/download/${cid}`, {
params: { chunk_size: chunkSize },
responseType: 'stream',
});
const chunks = [];
for await (const chunk of response.data) {
chunks.push(chunk);
}
return Buffer.concat(chunks);
}
async getTensor(cid, sliceSpec = null) {
const params = {};
if (sliceSpec) {
params.slice = sliceSpec;
}
const response = await this.client.get(`/v1/tensor/${cid}`, {
params,
responseType: 'arraybuffer',
});
return Buffer.from(response.data);
}
async getTensorInfo(cid) {
const response = await this.client.get(`/v1/tensor/${cid}/info`);
return response.data;
}
async getTensorArrow(cid, sliceSpec = null) {
const params = {};
if (sliceSpec) {
params.slice = sliceSpec;
}
const response = await this.client.get(`/v1/tensor/${cid}/arrow`, {
params,
responseType: 'arraybuffer',
});
const table = tableFromIPC(response.data);
const metadata = {
tensor_shape: response.headers['x-tensor-shape'] || '[]',
tensor_dtype: response.headers['x-tensor-dtype'] || 'unknown',
tensor_elements: response.headers['x-tensor-elements'] || '0',
};
return { table, metadata };
}
async getId() {
const response = await this.client.post('/api/v0/id');
return response.data;
}
async getVersion() {
const response = await this.client.post('/api/v0/version');
return response.data;
}
async getPeers() {
const response = await this.client.post('/api/v0/swarm/peers');
return response.data.Peers || [];
}
async getBandwidthStats() {
const response = await this.client.post('/api/v0/stats/bw');
return response.data;
}
connectWebSocket(onMessage, onError) {
const wsUrl = this.baseUrl.replace(/^http/, 'ws') + '/ws';
const ws = new WebSocket(wsUrl);
ws.on('open', () => {
console.log('WebSocket connected');
});
ws.on('message', (data) => {
const message = JSON.parse(data.toString());
onMessage(message);
});
ws.on('error', (error) => {
if (onError) {
onError(error);
}
});
return ws;
}
subscribe(ws, topic) {
const message = {
type: 'Subscribe',
topic: topic,
};
ws.send(JSON.stringify(message));
}
}
async function main() {
console.log('=== IPFRS JavaScript Client Example ===\n');
const client = new IPFRSClient('http://localhost:8080');
console.log('1. File Upload and Download');
try {
const testFile = '/tmp/test_ipfrs_js.txt';
fs.writeFileSync(testFile, 'Hello, IPFRS! This is a test file from JavaScript.');
const result = await client.addFile(testFile);
const cid = result.Hash;
console.log(` Uploaded file: ${cid} (${result.Size} bytes)`);
const content = await client.cat(cid);
console.log(` Downloaded: ${content.toString()}`);
} catch (error) {
console.error(` Error: ${error.message}`);
}
console.log('\n2. Batch Block Operations');
try {
console.log(' (Skipping - would need valid CIDs)');
} catch (error) {
console.error(` Error: ${error.message}`);
}
console.log('\n3. Tensor Operations with Apache Arrow');
try {
console.log(' (Skipping - no tensor CID available)');
} catch (error) {
console.error(` Error: ${error.message}`);
}
console.log('\n4. Node Information');
try {
const version = await client.getVersion();
console.log(` Version: ${version.Version || 'unknown'}`);
console.log(` System: ${version.System || 'unknown'}`);
} catch (error) {
console.error(` Error: ${error.message}`);
}
console.log('\n5. WebSocket Real-Time Events');
try {
console.log(' (Uncomment code to test WebSocket)');
} catch (error) {
console.error(` Error: ${error.message}`);
}
console.log('\n=== Example Complete ===');
}
if (require.main === module) {
main().catch(console.error);
}
module.exports = IPFRSClient;