mirror of
https://github.com/Gerald-Ha/HodlEye-Crypto-Price-Tracker.git
synced 2025-06-25 09:11:45 +00:00
194 lines
4.6 KiB
JavaScript
194 lines
4.6 KiB
JavaScript
const express = require("express");
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const cors = require("cors");
|
|
const http = require("http");
|
|
const WebSocket = require("ws");
|
|
|
|
|
|
const app = express();
|
|
app.use(cors());
|
|
app.use(express.json());
|
|
|
|
const server = http.createServer(app);
|
|
const wss = new WebSocket.Server({ server });
|
|
|
|
const clients = new Set();
|
|
|
|
/*
|
|
* Metadata
|
|
* Version: 1.0.6
|
|
* Author/Dev: Gerald Hasani
|
|
* Name: HodlEye Crypto Price Tracker
|
|
* Email: contact@gerald-hasani.com
|
|
* GitHub: https://github.com/Gerald-Ha
|
|
*/
|
|
|
|
const DATA_FILE = path.join(__dirname, "..", "data", "data.json");
|
|
|
|
|
|
if (!fs.existsSync(DATA_FILE)) {
|
|
fs.writeFileSync(
|
|
DATA_FILE,
|
|
JSON.stringify(
|
|
{
|
|
cryptos: ["BTC"],
|
|
alarms: [],
|
|
notifications: []
|
|
},
|
|
null,
|
|
2
|
|
)
|
|
);
|
|
}
|
|
|
|
function readData() {
|
|
return JSON.parse(fs.readFileSync(DATA_FILE, "utf8"));
|
|
}
|
|
|
|
function writeData(data) {
|
|
fs.writeFileSync(DATA_FILE, JSON.stringify(data, null, 2));
|
|
}
|
|
|
|
|
|
app.get("/api/update", (req, res) => {
|
|
const remoteUpdateUrl = "https://raw.githubusercontent.com/Gerald-Ha/HodlEye-Crypto-Price-Tracker/refs/heads/main/update.json";
|
|
fetch(remoteUpdateUrl)
|
|
.then(data => {
|
|
|
|
if (data.changelog) {
|
|
data.changelog = data.changelog.replace(/\n/g, "<br>");
|
|
}
|
|
|
|
res.header("Cache-Control", "no-cache, no-store, must-revalidate");
|
|
res.header("Pragma", "no-cache");
|
|
res.header("Expires", "0");
|
|
res.json(data);
|
|
})
|
|
.catch(error => {
|
|
console.error("Fehler beim Abrufen der remote update.json:", error);
|
|
res.status(500).json({ error: "Could not fetch update data" });
|
|
});
|
|
});
|
|
|
|
app.get("/api/cryptos", (req, res) => {
|
|
const data = readData();
|
|
res.json(data.cryptos);
|
|
});
|
|
|
|
app.post("/api/cryptos", (req, res) => {
|
|
const { symbol } = req.body;
|
|
if (!symbol) {
|
|
return res.status(400).json({ error: "Symbol is required." });
|
|
}
|
|
const data = readData();
|
|
const upperSymbol = symbol.toUpperCase();
|
|
if (!data.cryptos.includes(upperSymbol)) {
|
|
data.cryptos.push(upperSymbol);
|
|
writeData(data);
|
|
}
|
|
res.json(data.cryptos);
|
|
});
|
|
|
|
app.delete("/api/cryptos/:symbol", (req, res) => {
|
|
const symbol = req.params.symbol.toUpperCase();
|
|
const data = readData();
|
|
data.cryptos = data.cryptos.filter(s => s !== symbol);
|
|
writeData(data);
|
|
res.json({ success: true, cryptos: data.cryptos });
|
|
});
|
|
|
|
app.put("/api/cryptos", (req, res) => {
|
|
const { cryptoList } = req.body;
|
|
if (!Array.isArray(cryptoList)) {
|
|
return res.status(400).json({ error: "cryptoList must be an array." });
|
|
}
|
|
const data = readData();
|
|
data.cryptos = cryptoList;
|
|
writeData(data);
|
|
res.json({ success: true, cryptos: data.cryptos });
|
|
});
|
|
|
|
app.get("/api/alarms", (req, res) => {
|
|
const data = readData();
|
|
res.json(data.alarms);
|
|
});
|
|
|
|
app.post("/api/alarms", (req, res) => {
|
|
const { symbol, price, frequency, direction } = req.body;
|
|
if (!symbol || !price) {
|
|
return res.status(400).json({ error: "symbol and price are required." });
|
|
}
|
|
const data = readData();
|
|
const newAlarm = {
|
|
id: Date.now(),
|
|
symbol: symbol.toUpperCase(),
|
|
price: parseFloat(price),
|
|
frequency: frequency || "Once",
|
|
direction: direction || "Rising",
|
|
triggered: false
|
|
};
|
|
data.alarms.push(newAlarm);
|
|
writeData(data);
|
|
res.json(newAlarm);
|
|
});
|
|
|
|
app.delete("/api/alarms/:id", (req, res) => {
|
|
const alarmId = parseInt(req.params.id, 10);
|
|
const data = readData();
|
|
data.alarms = data.alarms.filter(a => a.id !== alarmId);
|
|
writeData(data);
|
|
res.json({ success: true, alarms: data.alarms });
|
|
});
|
|
|
|
app.get("/api/notifications", (req, res) => {
|
|
const data = readData();
|
|
res.json(data.notifications);
|
|
});
|
|
|
|
app.post("/api/notifications", (req, res) => {
|
|
const { message } = req.body;
|
|
if (!message) {
|
|
return res.status(400).json({ error: "message is required." });
|
|
}
|
|
const data = readData();
|
|
const entry = {
|
|
message,
|
|
timestamp: new Date().toISOString()
|
|
};
|
|
data.notifications.unshift(entry);
|
|
writeData(data);
|
|
|
|
|
|
clients.forEach((client) => {
|
|
if (client.readyState === WebSocket.OPEN) {
|
|
client.send(JSON.stringify(entry));
|
|
}
|
|
});
|
|
|
|
res.json(entry);
|
|
});
|
|
|
|
app.delete("/api/notifications", (req, res) => {
|
|
const data = readData();
|
|
data.notifications = [];
|
|
writeData(data);
|
|
res.json({ success: true });
|
|
});
|
|
|
|
app.use(express.static(path.join(__dirname, "..", "public")));
|
|
|
|
wss.on("connection", (ws) => {
|
|
console.log("Client verbunden");
|
|
clients.add(ws);
|
|
ws.on("close", () => {
|
|
console.log("Client getrennt");
|
|
clients.delete(ws);
|
|
});
|
|
});
|
|
|
|
const PORT = process.env.PORT || 3099;
|
|
server.listen(PORT, () => {
|
|
console.log(`Server läuft auf Port ${PORT}`);
|
|
});
|