mirror of
https://github.com/basicswap/basicswap.git
synced 2025-11-05 18:38:09 +01:00
284 lines
10 KiB
JavaScript
284 lines
10 KiB
JavaScript
const ConfigManager = (function() {
|
|
const state = {
|
|
isInitialized: false
|
|
};
|
|
|
|
function determineWebSocketPort() {
|
|
const wsPort =
|
|
window.ws_port ||
|
|
(typeof getWebSocketConfig === 'function' ? getWebSocketConfig().port : null) ||
|
|
'11700';
|
|
return wsPort;
|
|
}
|
|
|
|
const selectedWsPort = determineWebSocketPort();
|
|
|
|
const defaultConfig = {
|
|
cacheDuration: 10 * 60 * 1000,
|
|
requestTimeout: 60000,
|
|
wsPort: selectedWsPort,
|
|
cacheConfig: {
|
|
defaultTTL: 10 * 60 * 1000,
|
|
ttlSettings: {
|
|
prices: 5 * 60 * 1000,
|
|
chart: 5 * 60 * 1000,
|
|
historical: 60 * 60 * 1000,
|
|
volume: 30 * 60 * 1000,
|
|
offers: 2 * 60 * 1000,
|
|
identity: 15 * 60 * 1000
|
|
},
|
|
storage: {
|
|
maxSizeBytes: 10 * 1024 * 1024,
|
|
maxItems: 200
|
|
},
|
|
fallbackTTL: 24 * 60 * 60 * 1000
|
|
},
|
|
itemsPerPage: 50,
|
|
apiEndpoints: {
|
|
coinGecko: 'https://api.coingecko.com/api/v3',
|
|
volumeEndpoint: 'https://api.coingecko.com/api/v3/simple/price'
|
|
},
|
|
rateLimits: {
|
|
coingecko: {
|
|
requestsPerMinute: 50,
|
|
minInterval: 1200
|
|
}
|
|
},
|
|
retryDelays: [5000, 15000, 30000],
|
|
get coins() {
|
|
if (window.CoinManager) {
|
|
return window.CoinManager.getAllCoins();
|
|
}
|
|
console.warn('[ConfigManager] CoinManager not available, returning empty array');
|
|
return [];
|
|
},
|
|
chartConfig: {
|
|
colors: {
|
|
default: {
|
|
lineColor: 'rgba(77, 132, 240, 1)',
|
|
backgroundColor: 'rgba(77, 132, 240, 0.1)'
|
|
}
|
|
},
|
|
showVolume: false,
|
|
specialCoins: [''],
|
|
resolutions: {
|
|
year: { days: 365, interval: 'month' },
|
|
sixMonths: { days: 180, interval: 'daily' },
|
|
day: { days: 1, interval: 'hourly' }
|
|
},
|
|
currentResolution: 'year'
|
|
}
|
|
};
|
|
|
|
const publicAPI = {
|
|
...defaultConfig,
|
|
initialize: function(options = {}) {
|
|
if (state.isInitialized) {
|
|
console.warn('[ConfigManager] Already initialized');
|
|
return this;
|
|
}
|
|
if (options) {
|
|
Object.assign(this, options);
|
|
}
|
|
if (window.CleanupManager) {
|
|
window.CleanupManager.registerResource('configManager', this, (mgr) => mgr.dispose());
|
|
}
|
|
this.utils = utils;
|
|
state.isInitialized = true;
|
|
console.log('ConfigManager initialized');
|
|
return this;
|
|
},
|
|
getAPIKeys: function() {
|
|
if (typeof window.getAPIKeys === 'function') {
|
|
const apiKeys = window.getAPIKeys();
|
|
return {
|
|
coinGecko: apiKeys.coinGecko || ''
|
|
};
|
|
}
|
|
return {
|
|
coinGecko: ''
|
|
};
|
|
},
|
|
getCoinBackendId: function(coinName) {
|
|
if (!coinName) return null;
|
|
if (window.CoinManager) {
|
|
return window.CoinManager.getPriceKey(coinName);
|
|
}
|
|
if (window.CoinUtils) {
|
|
return window.CoinUtils.normalizeCoinName(coinName);
|
|
}
|
|
return typeof coinName === 'string' ? coinName.toLowerCase() : '';
|
|
},
|
|
coinMatches: function(offerCoin, filterCoin) {
|
|
if (!offerCoin || !filterCoin) return false;
|
|
if (window.CoinManager) {
|
|
return window.CoinManager.coinMatches(offerCoin, filterCoin);
|
|
}
|
|
if (window.CoinUtils) {
|
|
return window.CoinUtils.isSameCoin(offerCoin, filterCoin);
|
|
}
|
|
return offerCoin.toLowerCase() === filterCoin.toLowerCase();
|
|
},
|
|
update: function(path, value) {
|
|
const parts = path.split('.');
|
|
let current = this;
|
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
if (!current[parts[i]]) {
|
|
current[parts[i]] = {};
|
|
}
|
|
current = current[parts[i]];
|
|
}
|
|
current[parts[parts.length - 1]] = value;
|
|
return this;
|
|
},
|
|
get: function(path, defaultValue = null) {
|
|
const parts = path.split('.');
|
|
let current = this;
|
|
for (let i = 0; i < parts.length; i++) {
|
|
if (current === undefined || current === null) {
|
|
return defaultValue;
|
|
}
|
|
current = current[parts[i]];
|
|
}
|
|
return current !== undefined ? current : defaultValue;
|
|
},
|
|
dispose: function() {
|
|
state.isInitialized = false;
|
|
console.log('ConfigManager disposed');
|
|
}
|
|
};
|
|
|
|
const utils = {
|
|
formatNumber: function(number, decimals = 2) {
|
|
if (typeof number !== 'number' || isNaN(number)) {
|
|
console.warn('formatNumber received a non-number value:', number);
|
|
return '0';
|
|
}
|
|
try {
|
|
return new Intl.NumberFormat('en-US', {
|
|
minimumFractionDigits: decimals,
|
|
maximumFractionDigits: decimals
|
|
}).format(number);
|
|
} catch (e) {
|
|
return '0';
|
|
}
|
|
},
|
|
formatDate: function(timestamp, resolution) {
|
|
const date = new Date(timestamp);
|
|
const options = {
|
|
day: { hour: '2-digit', minute: '2-digit', hour12: true },
|
|
week: { month: 'short', day: 'numeric' },
|
|
month: { year: 'numeric', month: 'short', day: 'numeric' }
|
|
};
|
|
return date.toLocaleString('en-US', { ...options[resolution], timeZone: 'UTC' });
|
|
},
|
|
debounce: function(func, delay) {
|
|
let timeoutId;
|
|
return function(...args) {
|
|
clearTimeout(timeoutId);
|
|
timeoutId = CleanupManager.setTimeout(() => func(...args), delay);
|
|
};
|
|
},
|
|
formatTimeLeft: function(timestamp) {
|
|
const now = Math.floor(Date.now() / 1000);
|
|
if (timestamp <= now) return "Expired";
|
|
return this.formatTime(timestamp);
|
|
},
|
|
formatTime: function(timestamp, addAgoSuffix = false) {
|
|
const now = Math.floor(Date.now() / 1000);
|
|
const diff = Math.abs(now - timestamp);
|
|
let timeString;
|
|
if (diff < 60) {
|
|
timeString = `${diff} seconds`;
|
|
} else if (diff < 3600) {
|
|
timeString = `${Math.floor(diff / 60)} minutes`;
|
|
} else if (diff < 86400) {
|
|
timeString = `${Math.floor(diff / 3600)} hours`;
|
|
} else if (diff < 2592000) {
|
|
timeString = `${Math.floor(diff / 86400)} days`;
|
|
} else if (diff < 31536000) {
|
|
timeString = `${Math.floor(diff / 2592000)} months`;
|
|
} else {
|
|
timeString = `${Math.floor(diff / 31536000)} years`;
|
|
}
|
|
return addAgoSuffix ? `${timeString} ago` : timeString;
|
|
},
|
|
escapeHtml: function(unsafe) {
|
|
if (typeof unsafe !== 'string') {
|
|
console.warn('escapeHtml received a non-string value:', unsafe);
|
|
return '';
|
|
}
|
|
return unsafe
|
|
.replace(/&/g, "&")
|
|
.replace(/</g, "<")
|
|
.replace(/>/g, ">")
|
|
.replace(/"/g, """)
|
|
.replace(/'/g, "'");
|
|
},
|
|
formatPrice: function(coin, price) {
|
|
if (typeof price !== 'number' || isNaN(price)) {
|
|
console.warn(`Invalid price for ${coin}:`, price);
|
|
return 'N/A';
|
|
}
|
|
if (price < 0.000001) return price.toExponential(2);
|
|
if (price < 0.001) return price.toFixed(8);
|
|
if (price < 1) return price.toFixed(4);
|
|
if (price < 10) return price.toFixed(3);
|
|
if (price < 1000) return price.toFixed(2);
|
|
if (price < 100000) return price.toFixed(1);
|
|
return price.toFixed(0);
|
|
},
|
|
getEmptyPriceData: function() {
|
|
return {
|
|
'bitcoin': { usd: null, btc: null },
|
|
'bitcoin-cash': { usd: null, btc: null },
|
|
'dash': { usd: null, btc: null },
|
|
'dogecoin': { usd: null, btc: null },
|
|
'decred': { usd: null, btc: null },
|
|
'namecoin': { usd: null, btc: null },
|
|
'litecoin': { usd: null, btc: null },
|
|
'particl': { usd: null, btc: null },
|
|
'pivx': { usd: null, btc: null },
|
|
'monero': { usd: null, btc: null },
|
|
'zano': { usd: null, btc: null },
|
|
'wownero': { usd: null, btc: null },
|
|
'firo': { usd: null, btc: null }
|
|
};
|
|
},
|
|
getCoinSymbol: function(fullName) {
|
|
if (window.CoinManager) {
|
|
return window.CoinManager.getSymbol(fullName) || fullName;
|
|
}
|
|
return fullName;
|
|
}
|
|
};
|
|
return publicAPI;
|
|
})();
|
|
|
|
window.logger = {
|
|
log: function(message) {
|
|
console.log(`[AppLog] ${new Date().toISOString()}: ${message}`);
|
|
},
|
|
warn: function(message) {
|
|
console.warn(`[AppWarn] ${new Date().toISOString()}: ${message}`);
|
|
},
|
|
error: function(message) {
|
|
console.error(`[AppError] ${new Date().toISOString()}: ${message}`);
|
|
}
|
|
};
|
|
|
|
window.config = ConfigManager;
|
|
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
if (!window.configManagerInitialized) {
|
|
ConfigManager.initialize();
|
|
window.configManagerInitialized = true;
|
|
}
|
|
});
|
|
|
|
if (typeof module !== 'undefined') {
|
|
module.exports = ConfigManager;
|
|
}
|
|
|
|
console.log('ConfigManager initialized');
|