Compare commits

..

6 commits

7 changed files with 94 additions and 21 deletions

View file

@ -5,7 +5,7 @@
name: DATABASE_NAME name: DATABASE_NAME
password: DATABASE_PASSWORD password: DATABASE_PASSWORD
} }
currecy: { currency: {
collecting: { collecting: {
fiat: true fiat: true
crypto: false crypto: false
@ -27,6 +27,9 @@
USDT, USDT,
TON TON
] ]
api_keys: {
coinmarketcap: TOKEN_COINMARKETCAP
}
} }
schedule: 30 8 * * * schedule: 30 8 * * *
} }

View file

@ -1,8 +1,6 @@
const pg = require('pg'); const pg = require('pg');
const fs = require('fs'); const fs = require('fs');
const hjson = require('hjson'); const config = require('../utils/load_config.js')();
const config = hjson.parse(fs.readFileSync('config.hjson', 'utf-8'));
const pool = new pg.Pool({ const pool = new pg.Pool({
user: config['database']['user'], user: config['database']['user'],

25
main.js
View file

@ -1,12 +1,11 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const hjson = require('hjson');
const schedule = require('node-schedule'); const schedule = require('node-schedule');
const cron = require('cron-validator'); const cron = require('cron-validator');
const { validateCurrency } = require('./models/Currency.js'); const { validateCurrency } = require('./models/Currency.js');
const { create_table, pool } = require('./database/data.js'); const { create_table, pool } = require('./database/data.js');
const config = hjson.parse(fs.readFileSync('config.hjson', 'utf-8')); const config = require('./utils/load_config.js')();
async function main() { async function main() {
if (!config['schedule']) if (!config['schedule'])
@ -34,29 +33,29 @@ async function main() {
console.log('Running scheduled task at:', new Date()); console.log('Running scheduled task at:', new Date());
for (const srv of services) { for (const srv of services) {
try { const results = await srv.parseCurrencies();
const result = await srv.parseCurrencies();
if (Array.isArray(results) && results.length > 0) {
if (result) { for (const result of results) {
try { try {
const currency = await validateCurrency(result); const currency = await validateCurrency(result);
await pool.query( await pool.query(
'INSERT INTO currency (from_currency, conv_currency, rate, date) ' + 'INSERT INTO currency (from_currency, conv_currency, rate, date) VALUES ($1, $2, $3, $4)',
'VALUES ($1, $2, $3, $4)',
[ [
currency.from_currency, currency.from_currency,
currency.conv_currency, currency.conv_currency,
currency.rate, currency.rate,
currency.date, currency.date,
]); ]
);
} catch (validationError) { } catch (validationError) {
console.error(validationError); console.error(validationError);
} }
} }
} catch (err) { } else {
console.error(`Error in service ${srv.name || 'unknown'}:`, err); console.error("Data not received for writing to the database.");
} }
} }
}); });

View file

@ -1,14 +1,16 @@
const Joi = require('joi'); const Joi = require('joi');
const currencySchema = Joi.object({ const currencySchema = Joi.object({
from_currency: Joi.string().length(3).required().messages({ from_currency: Joi.string().min(3).max(4).required().messages({
'string.base': 'from_currency must be a string', 'string.base': 'from_currency must be a string',
'string.length': 'from_currency must be exactly 3 characters long', 'string.min': 'from_currency must be at least 3 characters long',
'string.max': 'from_currency must be no more than 4 characters long',
'any.required': 'from_currency is required' 'any.required': 'from_currency is required'
}), }),
conv_currency: Joi.string().length(3).required().messages({ conv_currency: Joi.string().min(3).max(4).required().messages({
'string.base': 'conv_currency must be a string', 'string.base': 'conv_currency must be a string',
'string.length': 'conv_currency must be exactly 3 characters long', 'string.min': 'conv_currency must be at least 3 characters long',
'string.max': 'conv_currency must be no more than 4 characters long',
'any.required': 'conv_currency is required' 'any.required': 'conv_currency is required'
}), }),
date: Joi.date().iso().required().messages({ date: Joi.date().iso().required().messages({

47
services/coinmarketcap.js Normal file
View file

@ -0,0 +1,47 @@
const axios = require('axios');
const config = require('../utils/load_config.js')();
const { truncate_number } = require('../utils/truncate_number.js');
module.exports = {
parseCurrencies: async () => {
const promises = config['currency']['crypto'].map(fromCurrency => {
return config['currency']['crypto'].map(convCurrency => {
if (fromCurrency === convCurrency) return Promise.resolve(null);
return axios.get(
'https://pro-api.coinmarketcap.com/v1/cryptocurrency/quotes/latest',
{
params: {
symbol: fromCurrency,
convert: convCurrency,
},
headers: {
'X-CMC_PRO_API_KEY': config['currency']['api_keys']['coinmarketcap'],
}
}
)
.then((res) => {
const data = res.data.data[fromCurrency].quote[convCurrency];
const truncatedPriceStr = truncate_number(data.price, 3);
const rate = parseFloat(truncatedPriceStr);
return {
from_currency: fromCurrency,
conv_currency: convCurrency,
rate: rate,
date: new Date(data['last_updated']).toISOString().substring(0, 10),
};
})
.catch((err) => {
console.error(err.respone.data);
return null;
});
});
});
const flattenedPromises = promises.flat();
const results = await Promise.all(flattenedPromises);
return results.filter(result => result !== null);
}
};

10
utils/load_config.js Normal file
View file

@ -0,0 +1,10 @@
const fs = require('fs');
const hjson = require('hjson');
const config = () => {
if (!fs.existsSync('../config.hjson')) throw new Error('Config not found');
return hjson.parse(fs.readFileSync('../config.hjson', 'utf-8'));
}
module.exports = config;

14
utils/truncate_number.js Normal file
View file

@ -0,0 +1,14 @@
function truncate_number(value, decimals) {
const valueStr = value.toString();
const dotIndex = valueStr.indexOf('.');
if (dotIndex === -1) return valueStr;
const desiredLength = dotIndex + decimals + 1;
let truncated = valueStr.slice(0, desiredLength);
if (parseFloat(truncated) === 0 && value > 0) {
return valueStr;
}
return truncated;
}
module.exports = { truncate_number };