Redo
This commit is contained in:
		
							
								
								
									
										402
									
								
								main.js
									
									
									
									
									
								
							
							
						
						
									
										402
									
								
								main.js
									
									
									
									
									
								
							| @@ -1,233 +1,287 @@ | |||||||
| require('dotenv').config(); | require('dotenv').config(); | ||||||
| const { Client, GatewayIntentBits, EmbedBuilder } = require('discord.js'); | const { Client, GatewayIntentBits, EmbedBuilder } = require('discord.js'); | ||||||
| const fs = require('fs'); | const sqlite3 = require('sqlite3').verbose(); | ||||||
| const path = require('path'); | const path = require('path'); | ||||||
|  |  | ||||||
| let priceHistory = { |  | ||||||
|   currentPrice: 0, |  | ||||||
|   prices: [{ |  | ||||||
|       time: Date.now(), |  | ||||||
|       price: 0, |  | ||||||
|   }] |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| const client = new Client({ | const client = new Client({ | ||||||
|   intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages], |   intents: [GatewayIntentBits.Guilds, GatewayIntentBits.GuildMessages], | ||||||
| }); | }); | ||||||
|  |  | ||||||
| const solanaPriceChannelId = process.env.SOLANA_PRICE_CHANNEL_ID; | const PRICE_CHECK_INTERVAL = 60000; | ||||||
| const announcementsChannelId = process.env.ANNOUNCEMENTS_CHANNEL_ID; | const PRICE_INCREASE_THRESHOLD = 2.5; | ||||||
| const solanaDataFile = './data/solana.json'; | const DB_PATH = path.join(__dirname, 'data', 'solana.db'); | ||||||
| let lastAnnouncedPrice; |  | ||||||
| let lastPriceMessageId; |  | ||||||
|  |  | ||||||
| client.once('ready', async () => { | const db = new sqlite3.Database(DB_PATH, (err) => { | ||||||
|   console.log('Bot is online!'); |   if (err) console.error('Database opening error: ', err); | ||||||
|   let solanaData = readSolanaData(); |   initializeDatabase(); | ||||||
|   if (solanaData) { |  | ||||||
|     priceHistory = solanaData; |  | ||||||
|     lastAnnouncedPrice = solanaData.lastAnnouncedPrice; |  | ||||||
|     lastPriceMessageId = solanaData.lastPriceMessageId; |  | ||||||
|   } |  | ||||||
|   immediatePriceCheckAndAnnounce(); |  | ||||||
|   checkPriceContinuously(); |  | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | function initializeDatabase() { | ||||||
|  |   db.serialize(() => { | ||||||
|  |     db.run(`CREATE TABLE IF NOT EXISTS price_history ( | ||||||
|  |       id INTEGER PRIMARY KEY AUTOINCREMENT, | ||||||
|  |       timestamp INTEGER NOT NULL, | ||||||
|  |       price REAL NOT NULL | ||||||
|  |     )`); | ||||||
|  |  | ||||||
|  |     db.run(`CREATE TABLE IF NOT EXISTS bot_state ( | ||||||
|  |       key TEXT PRIMARY KEY, | ||||||
|  |       value TEXT NOT NULL | ||||||
|  |     )`); | ||||||
|  |  | ||||||
|  |     db.run('CREATE INDEX IF NOT EXISTS idx_timestamp ON price_history(timestamp)'); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |  | ||||||
| async function fetchSolanaPrice() { | async function fetchSolanaPrice() { | ||||||
|   const cryptocompareApiUrl = 'https://min-api.cryptocompare.com/data/price?fsym=SOL&tsyms=USD'; |  | ||||||
|   try { |   try { | ||||||
|     const fetch = (await import('node-fetch')).default; |     const fetch = (await import('node-fetch')).default; | ||||||
|     const response = await fetch(cryptocompareApiUrl); |     const response = await fetch('https://min-api.cryptocompare.com/data/price?fsym=SOL&tsyms=USD'); | ||||||
|     if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); |     if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); | ||||||
|     const data = await response.json(); |     const data = await response.json(); | ||||||
|     return parseFloat(data.USD).toFixed(2); |     return parseFloat(data.USD).toFixed(2); | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     console.error('Error fetching Solana price:', error); |     console.error('Error fetching Solana price:', error); | ||||||
|     setTimeout(fetchSolanaPriceAndUpdateHistory, 5 * 60 * 1000); |  | ||||||
|     return null; |     return null; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| function pruneOldData() { | function savePriceData(price) { | ||||||
|   const sixHoursInMilliseconds = 6 * 60 * 60 * 1000; |   return new Promise((resolve, reject) => { | ||||||
|   const oneDayInMilliseconds = 24 * 60 * 60 * 1000; |     const timestamp = Date.now(); | ||||||
|   const cutoffTime1Day = Date.now() - oneDayInMilliseconds; |     db.run('INSERT INTO price_history (timestamp, price) VALUES (?, ?)', | ||||||
|  |       [timestamp, price], | ||||||
|   priceHistory.prices = priceHistory.prices.filter(pricePoint => pricePoint.time > cutoffTime1Day); |       (err) => err ? reject(err) : resolve()); | ||||||
|  |   }); | ||||||
|   if (priceHistory.prices.length < (sixHoursInMilliseconds / (60 * 1000))) { |  | ||||||
|     console.warn("Warning: Not enough data points for accurate 6-hour calculations."); |  | ||||||
|   } |  | ||||||
|   if (priceHistory.prices.length < (oneDayInMilliseconds / (60 * 1000))) { |  | ||||||
|     console.warn("Warning: Not enough data points for accurate 1-day calculations."); |  | ||||||
|   } |  | ||||||
| } | } | ||||||
|  |  | ||||||
| async function fetchSolanaPriceAndUpdateHistory() { | function getLastAnnouncedPrice() { | ||||||
|   const currentPrice = await fetchSolanaPrice(); |   return new Promise((resolve, reject) => { | ||||||
|   if (currentPrice) { |     db.get('SELECT value FROM bot_state WHERE key = "lastAnnouncedPrice"', | ||||||
|     pruneOldData(); |       (err, row) => { | ||||||
|  |         if (err) { | ||||||
|     priceHistory.prices.push({ time: Date.now(), price: currentPrice }); |           console.error('Error getting last announced price:', err); | ||||||
|     priceHistory.currentPrice = currentPrice; |           resolve(null); | ||||||
|  |  | ||||||
|     saveSolanaData(priceHistory); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function immediatePriceCheckAndAnnounce() { |  | ||||||
|   const solanaData = readSolanaData(); |  | ||||||
|   const lastKnownPrice = solanaData ? solanaData.price : null; |  | ||||||
|   const currentPrice = fetchSolanaPrice(); |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   const now = Date.now(); |  | ||||||
|  |  | ||||||
|   function calculateChanges() { |  | ||||||
|   const latestPrice = parseFloat(priceHistory.currentPrice); |  | ||||||
|   let oneMinChange = { percent: 0, dollar: 0 }; |  | ||||||
|   let fiveMinChange = { percent: 0, dollar: 0 }; |  | ||||||
|   let oneHourChange = { percent: 0, dollar: 0 }; |  | ||||||
|   let sixHourChange = { percent: 0, dollar: 0 } |  | ||||||
|   let oneDayChange = { percent: 0, dollar: 0 }; |  | ||||||
|  |  | ||||||
|   const now = Date.now(); |  | ||||||
|  |  | ||||||
|   function findPriceAgo(minutesAgo) { |  | ||||||
|     const targetTime = now - minutesAgo * 60 * 1000; |  | ||||||
|     return priceHistory.prices.reduce((prev, curr) => { |  | ||||||
|       return Math.abs(curr.time - targetTime) < Math.abs(prev.time - targetTime) ? curr : prev; |  | ||||||
|     }, priceHistory.prices[0]); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (priceHistory.prices.length >= 2) { |  | ||||||
|     const oneMinAgoPrice = parseFloat(findPriceAgo(1).price); |  | ||||||
|     oneMinChange.percent = ((latestPrice - oneMinAgoPrice) / oneMinAgoPrice) * 100; |  | ||||||
|     oneMinChange.dollar = latestPrice - oneMinAgoPrice; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (priceHistory.prices.length >= 6) { |  | ||||||
|     const fiveMinAgoPrice = parseFloat(findPriceAgo(5).price); |  | ||||||
|     fiveMinChange.percent = ((latestPrice - fiveMinAgoPrice) / fiveMinAgoPrice) * 100; |  | ||||||
|     fiveMinChange.dollar = latestPrice - fiveMinAgoPrice; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (priceHistory.prices.length >= 61) { |  | ||||||
|     const oneHourAgoPrice = parseFloat(findPriceAgo(60).price); |  | ||||||
|     oneHourChange.percent = ((latestPrice - oneHourAgoPrice) / oneHourAgoPrice) * 100; |  | ||||||
|     oneHourChange.dollar = latestPrice - oneHourAgoPrice; |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (priceHistory.prices.length >= 1440) { |  | ||||||
|     const oneDayAgoPrice = parseFloat(findPriceAgo(1440).price); |  | ||||||
|     oneDayChange.percent = ((latestPrice - oneDayAgoPrice) / oneDayAgoPrice) * 100; |  | ||||||
|     oneDayChange.dollar = latestPrice - oneDayAgoPrice; |  | ||||||
|         } else { |         } else { | ||||||
|     console.log("Insufficient data for 1-day change calculation."); |           resolve(row ? parseFloat(row.value) : null); | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |   }); | ||||||
| } | } | ||||||
|  |  | ||||||
|   if (priceHistory.prices.length >= 360) { | function updateLastAnnouncedPrice(price) { | ||||||
|     const sixHourAgoPrice = parseFloat(findPriceAgo(360).price); |   return new Promise((resolve, reject) => { | ||||||
|     sixHourChange.percent = ((latestPrice - sixHourAgoPrice) / sixHourAgoPrice) * 100; |     db.run('INSERT OR REPLACE INTO bot_state (key, value) VALUES (?, ?)', | ||||||
|     sixHourChange.dollar = latestPrice - sixHourAgoPrice; |       ['lastAnnouncedPrice', price.toString()], | ||||||
|  |       (err) => { | ||||||
|  |         if (err) { | ||||||
|  |           console.error('Error updating last announced price:', err); | ||||||
|  |           resolve(false); | ||||||
|  |         } else { | ||||||
|  |           resolve(true); | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |   }); | ||||||
| } | } | ||||||
|  |  | ||||||
|   return { oneMinChange, fiveMinChange, oneHourChange, sixHourChange, oneDayChange }; | function getTimeBasedPrice(minutesAgo) { | ||||||
|  |   return new Promise((resolve) => { | ||||||
|  |     const timestamp = Date.now() - (minutesAgo * 60 * 1000); | ||||||
|  |     db.get( | ||||||
|  |       `SELECT price FROM price_history  | ||||||
|  |        WHERE timestamp <= ?  | ||||||
|  |        ORDER BY timestamp DESC LIMIT 1`, | ||||||
|  |       [timestamp], | ||||||
|  |       (err, row) => { | ||||||
|  |         if (err) { | ||||||
|  |           console.error(`Error getting price from ${minutesAgo} minutes ago:`, err); | ||||||
|  |           resolve(null); | ||||||
|  |         } else { | ||||||
|  |           resolve(row?.price || null); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
| } | } | ||||||
|  |  | ||||||
| async function sendNewPriceMessage(embed) { | async function calculateChanges(currentPrice) { | ||||||
|   const sentMessage = await solanaPriceChannel.send({ embeds: [embed] }); |   try { | ||||||
|   lastPriceMessageId = sentMessage.id; |     const [oneMinAgo, fiveMinAgo, oneHourAgo, sixHourAgo, oneDayAgo] = await Promise.all([ | ||||||
|  |       getTimeBasedPrice(1), | ||||||
|  |       getTimeBasedPrice(5), | ||||||
|  |       getTimeBasedPrice(60), | ||||||
|  |       getTimeBasedPrice(360), | ||||||
|  |       getTimeBasedPrice(1440) | ||||||
|  |     ]); | ||||||
|  |  | ||||||
|   saveSolanaData({ ...priceHistory, lastPriceMessageId: sentMessage.id }); |     const calculateChange = (oldPrice) => { | ||||||
|  |       if (!oldPrice) return { percent: 0, dollar: 0 }; | ||||||
|  |       const dollarChange = currentPrice - oldPrice; | ||||||
|  |       const percentChange = (dollarChange / oldPrice) * 100; | ||||||
|  |       return { percent: percentChange, dollar: dollarChange }; | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     return { | ||||||
|  |       oneMin: calculateChange(oneMinAgo), | ||||||
|  |       fiveMin: calculateChange(fiveMinAgo), | ||||||
|  |       oneHour: calculateChange(oneHourAgo), | ||||||
|  |       sixHour: calculateChange(sixHourAgo), | ||||||
|  |       oneDay: calculateChange(oneDayAgo) | ||||||
|  |     }; | ||||||
|  |   } catch (error) { | ||||||
|  |     console.error('Error calculating changes:', error); | ||||||
|  |     return { | ||||||
|  |       oneMin: { percent: 0, dollar: 0 }, | ||||||
|  |       fiveMin: { percent: 0, dollar: 0 }, | ||||||
|  |       oneHour: { percent: 0, dollar: 0 }, | ||||||
|  |       sixHour: { percent: 0, dollar: 0 }, | ||||||
|  |       oneDay: { percent: 0, dollar: 0 } | ||||||
|  |     }; | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| async function sendNewPriceMessage(solanaPriceChannel, embed) { | async function createPriceEmbed(currentPrice, changes) { | ||||||
|   const sentMessage = await solanaPriceChannel.send({ embeds: [embed] }); |  | ||||||
|   lastPriceMessageId = sentMessage.id; |  | ||||||
|  |  | ||||||
|   saveSolanaData({ ...priceHistory, lastPriceMessageId: sentMessage.id }); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| async function checkPriceContinuously() { |  | ||||||
|   await fetchSolanaPriceAndUpdateHistory(); |  | ||||||
|   const { oneMinChange, fiveMinChange, oneHourChange, sixHourChange, oneDayChange } = calculateChanges(); |  | ||||||
|  |  | ||||||
|   console.log(`Current Price: ${priceHistory.currentPrice}`); |  | ||||||
|  |  | ||||||
|   const randomColor = Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0'); |   const randomColor = Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0'); | ||||||
|  |  | ||||||
|   const embed = new EmbedBuilder() |   return new EmbedBuilder() | ||||||
|     .setColor(`#${randomColor}`) |     .setColor(`#${randomColor}`) | ||||||
|     .setThumbnail('https://solana.com/src/img/branding/solanaLogoMark.png') |     .setThumbnail('https://solana.com/src/img/branding/solanaLogoMark.png') | ||||||
|     .setTitle('Solana (SOL) Price Update') |     .setTitle('Solana (SOL) Price Update') | ||||||
|     .setURL('https://coinmarketcap.com/currencies/solana/') |     .setURL('https://coinmarketcap.com/currencies/solana/') | ||||||
|     .setDescription(`**Current Price: \`$${priceHistory.currentPrice}\`**`) |     .setDescription(`**Current Price: \`$${currentPrice}\`**`) | ||||||
|     .addFields([ |     .addFields([ | ||||||
|       { name: '💰 Current Price', value: `**\`$${priceHistory.currentPrice}\`**`, inline: false }, |       { name: '💰 Current Price', value: `**\`$${currentPrice}\`**`, inline: false }, | ||||||
|       { name: '1 Minute Change', value: `${oneMinChange.percent.toFixed(2)}% (${oneMinChange.dollar.toFixed(2)} USD)`, inline: true }, |       { name: '1 Minute Change', value: `${changes.oneMin.percent.toFixed(2)}% (${changes.oneMin.dollar.toFixed(2)} USD)`, inline: true }, | ||||||
|       { name: '5 Minute Change', value: `${fiveMinChange.percent.toFixed(2)}% (${fiveMinChange.dollar.toFixed(2)} USD)`, inline: true }, |       { name: '5 Minute Change', value: `${changes.fiveMin.percent.toFixed(2)}% (${changes.fiveMin.dollar.toFixed(2)} USD)`, inline: true }, | ||||||
|       { name: '1 Hour Change', value: `${oneHourChange.percent.toFixed(2)}% (${oneHourChange.dollar.toFixed(2)} USD)`, inline: true }, |       { name: '1 Hour Change', value: `${changes.oneHour.percent.toFixed(2)}% (${changes.oneHour.dollar.toFixed(2)} USD)`, inline: true }, | ||||||
|       { name: '6 Hour Change', value: `${sixHourChange.percent.toFixed(2)}% (${sixHourChange.dollar.toFixed(2)} USD)`, inline: true }, |       { name: '6 Hour Change', value: `${changes.sixHour.percent.toFixed(2)}% (${changes.sixHour.dollar.toFixed(2)} USD)`, inline: true }, | ||||||
|       { name: '1 Day Change', value: `${oneDayChange.percent.toFixed(2)}% (${oneDayChange.dollar.toFixed(2)} USD)`, inline: true } |       { name: '1 Day Change', value: `${changes.oneDay.percent.toFixed(2)}% (${changes.oneDay.dollar.toFixed(2)} USD)`, inline: true } | ||||||
|     ]) |     ]) | ||||||
|     .setTimestamp() |     .setTimestamp() | ||||||
|     .setImage(process.env.IMAGE_URL); |     .setImage(process.env.IMAGE_URL); | ||||||
|  |  | ||||||
|   const solanaPriceChannel = await client.channels.fetch(solanaPriceChannelId); |  | ||||||
|  |  | ||||||
|   if (lastPriceMessageId) { |  | ||||||
|     try { |  | ||||||
|       const message = await solanaPriceChannel.messages.fetch(lastPriceMessageId); |  | ||||||
|       await message.edit({ embeds: [embed] }); |  | ||||||
|     } catch (error) { |  | ||||||
|       console.error('Error updating price message, sending a new one:', error); |  | ||||||
|       sendNewPriceMessage(solanaPriceChannel, embed); |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | async function getMessageId() { | ||||||
|  |   return new Promise((resolve) => { | ||||||
|  |     db.get('SELECT value FROM bot_state WHERE key = "priceMessageId"', | ||||||
|  |       (err, row) => { | ||||||
|  |         if (err) { | ||||||
|  |           console.error('Error getting message ID:', err); | ||||||
|  |           resolve(null); | ||||||
|         } else { |         } else { | ||||||
|     console.log('No lastPriceMessageId found, sending a new message.'); |           resolve(row?.value || null); | ||||||
|     sendNewPriceMessage(solanaPriceChannel, embed); |         } | ||||||
|  |       }); | ||||||
|  |   }); | ||||||
| } | } | ||||||
|  |  | ||||||
|   if (lastAnnouncedPrice !== null && (parseFloat(priceHistory.currentPrice) - lastAnnouncedPrice >= 2.5)) { | async function updateMessageId(messageId) { | ||||||
|     const announcementsChannel = await client.channels.fetch(announcementsChannelId); |   return new Promise((resolve) => { | ||||||
|     await announcementsChannel.send(`@everyone Solana price has increased significantly! Current price: $${priceHistory.currentPrice}`); |     db.run('INSERT OR REPLACE INTO bot_state (key, value) VALUES (?, ?)', | ||||||
|     lastAnnouncedPrice = parseFloat(priceHistory.currentPrice); |       ['priceMessageId', messageId], | ||||||
|     saveSolanaData({ ...priceHistory, lastAnnouncedPrice }); |       err => { | ||||||
|  |         if (err) { | ||||||
|  |           console.error('Error updating message ID:', err); | ||||||
|  |           resolve(false); | ||||||
|  |         } else { | ||||||
|  |           resolve(true); | ||||||
|  |         } | ||||||
|  |       }); | ||||||
|  |   }); | ||||||
| } | } | ||||||
|  |  | ||||||
|   setTimeout(checkPriceContinuously, 60000); | async function updatePriceMessage(channel, currentPrice) { | ||||||
| } |  | ||||||
|  |  | ||||||
| function saveSolanaData(data) { |  | ||||||
|   const dir = path.dirname(solanaDataFile); |  | ||||||
|   if (!fs.existsSync(dir)) { |  | ||||||
|     fs.mkdirSync(dir, { recursive: true }); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   const dataToSave = { |  | ||||||
|     ...data, |  | ||||||
|     lastAnnouncedPrice: lastAnnouncedPrice, |  | ||||||
|   }; |  | ||||||
|  |  | ||||||
|   fs.writeFileSync(solanaDataFile, JSON.stringify(dataToSave, null, 2), 'utf8'); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function readSolanaData() { |  | ||||||
|   try { |   try { | ||||||
|     if (fs.existsSync(solanaDataFile)) { |     const changes = await calculateChanges(currentPrice); | ||||||
|       const fileContent = fs.readFileSync(solanaDataFile, 'utf8'); |     const embed = await createPriceEmbed(currentPrice, changes); | ||||||
|       const data = JSON.parse(fileContent); |     let messageId = await getMessageId(); | ||||||
|  |     let success = false; | ||||||
|  |  | ||||||
|       lastAnnouncedPrice = data.lastAnnouncedPrice || null; |     if (messageId) { | ||||||
|       return data; |       try { | ||||||
|  |         const message = await channel.messages.fetch(messageId); | ||||||
|  |         await message.edit({ embeds: [embed] }); | ||||||
|  |         success = true; | ||||||
|  |       } catch (error) { | ||||||
|  |         console.error('Failed to edit existing message:', error); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!success) { | ||||||
|  |       try { | ||||||
|  |         const message = await channel.send({ embeds: [embed] }); | ||||||
|  |         await updateMessageId(message.id); | ||||||
|  |       } catch (error) { | ||||||
|  |         console.error('Failed to send new message:', error); | ||||||
|  |         await new Promise(resolve => setTimeout(resolve, 5000)); | ||||||
|  |         try { | ||||||
|  |           const message = await channel.send({ embeds: [embed] }); | ||||||
|  |           await updateMessageId(message.id); | ||||||
|  |         } catch (retryError) { | ||||||
|  |           console.error('Failed to send message after retry:', retryError); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|     } |     } | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     console.error('Error reading Solana data:', error); |     console.error('Error in updatePriceMessage:', error); | ||||||
|   } |   } | ||||||
|   return null; |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | async function checkPriceAndAnnounce() { | ||||||
|  |   try { | ||||||
|  |     const currentPrice = await fetchSolanaPrice(); | ||||||
|  |     if (!currentPrice) { | ||||||
|  |       setTimeout(checkPriceAndAnnounce, PRICE_CHECK_INTERVAL); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     await savePriceData(currentPrice); | ||||||
|  |     const lastAnnouncedPrice = await getLastAnnouncedPrice(); | ||||||
|  |  | ||||||
|  |     const priceChannel = await client.channels.fetch(process.env.SOLANA_PRICE_CHANNEL_ID); | ||||||
|  |     await updatePriceMessage(priceChannel, currentPrice); | ||||||
|  |  | ||||||
|  |     if (lastAnnouncedPrice && (parseFloat(currentPrice) - lastAnnouncedPrice >= PRICE_INCREASE_THRESHOLD)) { | ||||||
|  |       const announcementsChannel = await client.channels.fetch(process.env.ANNOUNCEMENTS_CHANNEL_ID); | ||||||
|  |       await announcementsChannel.send( | ||||||
|  |         `@everyone Solana price has increased significantly! Current price: $${currentPrice} (Up $${(parseFloat(currentPrice) - lastAnnouncedPrice).toFixed(2)} from last announcement)` | ||||||
|  |       ); | ||||||
|  |       await updateLastAnnouncedPrice(parseFloat(currentPrice)); | ||||||
|  |     } | ||||||
|  |   } catch (error) { | ||||||
|  |     console.error('Error in price check and announce cycle:', error); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   setTimeout(checkPriceAndAnnounce, PRICE_CHECK_INTERVAL); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function cleanupOldData() { | ||||||
|  |   const oneDayAgo = Date.now() - (24 * 60 * 60 * 1000); | ||||||
|  |   db.run('DELETE FROM price_history WHERE timestamp < ?', [oneDayAgo], (err) => { | ||||||
|  |     if (err) console.error('Error cleaning up old data:', err); | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | db.on('error', (err) => { | ||||||
|  |   console.error('Database error:', err); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | client.once('ready', () => { | ||||||
|  |   console.log('Bot is online!'); | ||||||
|  |   checkPriceAndAnnounce(); | ||||||
|  |   setInterval(cleanupOldData, 6 * 60 * 60 * 1000); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | client.on('error', error => { | ||||||
|  |   console.error('Discord client error:', error); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | client.on('shardError', error => { | ||||||
|  |   console.error('Discord websocket error:', error); | ||||||
|  | }); | ||||||
|  |  | ||||||
|  | process.on('unhandledRejection', error => { | ||||||
|  |   console.error('Unhandled promise rejection:', error); | ||||||
|  | }); | ||||||
|  |  | ||||||
| client.login(process.env.DISCORD_BOT_TOKEN); | client.login(process.env.DISCORD_BOT_TOKEN); | ||||||
							
								
								
									
										1755
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1755
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,7 +1,8 @@ | |||||||
| { | { | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "discord.js": "^14.14.1", |     "discord.js": "^14.16.3", | ||||||
|     "dotenv": "^16.4.5", |     "dotenv": "^16.4.5", | ||||||
|     "node-fetch": "^3.3.2" |     "node-fetch": "^3.3.2", | ||||||
|  |     "sqlite3": "^5.1.7" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user