getting erc20 addresses optionally after running node

This commit is contained in:
Kumaraguru 2025-01-13 19:20:52 +00:00
parent 5a51c8a3a3
commit 60a9576fbe
No known key found for this signature in database
GPG Key ID: 4E4555A84ECD28F7
3 changed files with 174 additions and 33 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "codexstorage", "name": "codexstorage",
"version": "1.0.7", "version": "1.0.8",
"description": "CLI tool for Codex Storage", "description": "CLI tool for Codex Storage",
"main": "index.js", "main": "index.js",
"type": "module", "type": "module",

View File

@ -1,7 +1,7 @@
import { createSpinner } from 'nanospinner'; import { createSpinner } from 'nanospinner';
import { runCommand } from '../utils/command.js'; import { runCommand } from '../utils/command.js';
import { showErrorMessage, showInfoMessage, showSuccessMessage } from '../utils/messages.js'; import { showErrorMessage, showInfoMessage, showSuccessMessage } from '../utils/messages.js';
import { isNodeRunning, isCodexInstalled, logToSupabase } from '../services/nodeService.js'; import { isNodeRunning, isCodexInstalled, logToSupabase, startPeriodicLogging, getWalletAddress, setWalletAddress } from '../services/nodeService.js';
import inquirer from 'inquirer'; import inquirer from 'inquirer';
import boxen from 'boxen'; import boxen from 'boxen';
import chalk from 'chalk'; import chalk from 'chalk';
@ -11,6 +11,22 @@ import axios from 'axios';
const platform = os.platform(); const platform = os.platform();
async function promptForWalletAddress() {
const { wallet } = await inquirer.prompt([
{
type: 'input',
name: 'wallet',
message: 'Please enter your ERC20 wallet address (or press enter to skip):',
validate: (input) => {
if (!input) return true; // Allow empty input
if (/^0x[a-fA-F0-9]{40}$/.test(input)) return true;
return 'Please enter a valid ERC20 wallet address (0x followed by 40 hexadecimal characters) or press enter to skip';
}
}
]);
return wallet || null;
}
export async function runCodex(showNavigationMenu) { export async function runCodex(showNavigationMenu) {
const isInstalled = await isCodexInstalled(); const isInstalled = await isCodexInstalled();
if (!isInstalled) { if (!isInstalled) {
@ -84,7 +100,28 @@ export async function runCodex(showNavigationMenu) {
try { try {
const response = await axios.get('http://localhost:8080/api/codex/v1/debug/info'); const response = await axios.get('http://localhost:8080/api/codex/v1/debug/info');
if (response.status === 200) { if (response.status === 200) {
await logToSupabase(response.data); // Check if wallet exists
try {
const existingWallet = await getWalletAddress();
if (!existingWallet) {
console.log(showInfoMessage('[OPTIONAL] Please provide your ERC20 wallet address.'));
const wallet = await promptForWalletAddress();
if (wallet) {
await setWalletAddress(wallet);
console.log(showSuccessMessage('Wallet address saved successfully!'));
}
}
} catch (error) {
console.log(showErrorMessage('Failed to process wallet address. Continuing without wallet update.'));
}
// Start periodic logging
const stopLogging = await startPeriodicLogging();
nodeProcess.on('exit', () => {
stopLogging();
});
console.log(boxen( console.log(boxen(
chalk.cyan('We are logging some of your node\'s public data for improving the Codex experience'), chalk.cyan('We are logging some of your node\'s public data for improving the Codex experience'),
{ {
@ -131,10 +168,11 @@ async function showNodeDetails(data, showNavigationMenu) {
choices: [ choices: [
'1. View Connected Peers', '1. View Connected Peers',
'2. View Node Information', '2. View Node Information',
'3. Back to Main Menu', '3. Update Wallet Address',
'4. Exit' '4. Back to Main Menu',
'5. Exit'
], ],
pageSize: 4, pageSize: 5,
loop: true loop: true
} }
]); ]);
@ -183,8 +221,31 @@ async function showNodeDetails(data, showNavigationMenu) {
)); ));
return showNodeDetails(data, showNavigationMenu); return showNodeDetails(data, showNavigationMenu);
case '3': case '3':
return showNavigationMenu(); try {
const existingWallet = await getWalletAddress();
console.log(boxen(
`${chalk.cyan('Current wallet address:')}\n${existingWallet || 'Not set'}`,
{
padding: 1,
margin: 1,
borderStyle: 'round',
borderColor: 'blue'
}
));
const wallet = await promptForWalletAddress();
if (wallet) {
await setWalletAddress(wallet);
console.log(showSuccessMessage('Wallet address updated successfully!'));
}
} catch (error) {
console.log(showErrorMessage(`Failed to update wallet address: ${error.message}`));
}
return showNodeDetails(data, showNavigationMenu);
case '4': case '4':
return showNavigationMenu();
case '5':
process.exit(0); process.exit(0);
} }
} }

View File

@ -5,6 +5,21 @@ import os from 'os';
const platform = os.platform(); const platform = os.platform();
// Add a variable to store wallet address in memory
let currentWallet = null;
export async function setWalletAddress(wallet) {
// Basic ERC20 address validation
if (wallet && !/^0x[a-fA-F0-9]{40}$/.test(wallet)) {
throw new Error('Invalid ERC20 wallet address format');
}
currentWallet = wallet;
}
export async function getWalletAddress() {
return currentWallet;
}
export async function isNodeRunning() { export async function isNodeRunning() {
try { try {
const response = await axios.get('http://localhost:8080/api/codex/v1/debug/info'); const response = await axios.get('http://localhost:8080/api/codex/v1/debug/info');
@ -23,36 +38,53 @@ export async function isCodexInstalled() {
} }
} }
export async function logToSupabase(nodeData) { export async function logToSupabase(nodeData, retryCount = 3, retryDelay = 1000) {
try { const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const peerCount = nodeData.table.nodes ? nodeData.table.nodes.length : "0";
const payload = {
nodeId: nodeData.table.localNode.nodeId,
peerId: nodeData.table.localNode.peerId,
publicIp: nodeData.announceAddresses[0].split('/')[2],
version: nodeData.codex.version,
peerCount: peerCount == 0 ? "0" : peerCount,
port: nodeData.announceAddresses[0].split('/')[4],
listeningAddress: nodeData.table.localNode.address
};
const response = await axios.post('https://vfcnsjxahocmzefhckfz.supabase.co/functions/v1/codexnodes', payload, { for (let attempt = 1; attempt <= retryCount; attempt++) {
headers: { try {
'Content-Type': 'application/json' const peerCount = nodeData.table.nodes ? nodeData.table.nodes.length : "0";
} const payload = {
}); nodeId: nodeData.table.localNode.nodeId,
peerId: nodeData.table.localNode.peerId,
return response.status === 200; publicIp: nodeData.announceAddresses[0].split('/')[2],
} catch (error) { version: nodeData.codex.version,
console.error('Failed to log to Supabase:', error.message); peerCount: peerCount == 0 ? "0" : peerCount,
if (error.response) { port: nodeData.announceAddresses[0].split('/')[4],
console.error('Error response:', { listeningAddress: nodeData.table.localNode.address,
status: error.response.status, timestamp: new Date().toISOString(),
data: error.response.data wallet: currentWallet // Include wallet address in payload
};
const response = await axios.post('https://vfcnsjxahocmzefhckfz.supabase.co/functions/v1/codexnodes', payload, {
headers: {
'Content-Type': 'application/json'
},
timeout: 5000 // 5 second timeout
}); });
return response.status === 200;
} catch (error) {
const isLastAttempt = attempt === retryCount;
const isNetworkError = error.code === 'ENOTFOUND' || error.code === 'ETIMEDOUT' || error.code === 'ECONNREFUSED';
if (isLastAttempt || !isNetworkError) {
console.error(`Failed to log to Supabase (attempt ${attempt}/${retryCount}):`, error.message);
if (error.response) {
console.error('Error response:', {
status: error.response.status,
data: error.response.data
});
}
if (isLastAttempt) return false;
} else {
// Only log retry attempts for network errors
console.log(`Retrying Supabase log (attempt ${attempt}/${retryCount}) after ${retryDelay}ms...`);
await delay(retryDelay);
}
} }
return false;
} }
return false;
} }
export async function checkDependencies() { export async function checkDependencies() {
@ -70,4 +102,52 @@ export async function checkDependencies() {
} }
} }
return true; return true;
}
export async function startPeriodicLogging() {
const FIFTEEN_MINUTES = 15 * 60 * 1000; // 15 minutes in milliseconds
const logNodeInfo = async () => {
try {
const response = await axios.get('http://localhost:8080/api/codex/v1/debug/info');
if (response.status === 200) {
await logToSupabase(response.data);
}
} catch (error) {
// Silently handle any logging errors to not disrupt the node operation
console.error('Failed to log node info:', error.message);
}
};
// Initial log
await logNodeInfo();
// Set up periodic logging
const intervalId = setInterval(logNodeInfo, FIFTEEN_MINUTES);
// Return cleanup function
return () => clearInterval(intervalId);
}
export async function updateWalletAddress(nodeId, wallet) {
// Basic ERC20 address validation
if (!/^0x[a-fA-F0-9]{40}$/.test(wallet)) {
throw new Error('Invalid ERC20 wallet address format');
}
try {
const response = await axios.post('https://vfcnsjxahocmzefhckfz.supabase.co/functions/v1/wallet', {
nodeId,
wallet
}, {
headers: {
'Content-Type': 'application/json'
},
timeout: 5000
});
return response.status === 200;
} catch (error) {
console.error('Failed to update wallet address:', error.message);
throw error;
}
} }