-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathserver.js
More file actions
148 lines (121 loc) · 4.78 KB
/
Copy pathserver.js
File metadata and controls
148 lines (121 loc) · 4.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
const express = require("express");
require("dotenv").config();
const app = express();
app.use(express.json());
const PORT = process.env.PORT || 3000;
const API_TOKEN = process.env.NANOPAY_TOKEN;
const cors = require("cors");
app.use(cors());
app.post("/create-invoice", async (req, res) => {
console.log("Received request:", req.body);
const { username, amount, message } = req.body;
const streamchannel = process.env.STREAM_CHANNEL;
if (!username || !amount || parseFloat(amount) <= 0) {
return res.status(400).json({ error: "Invalid input" });
}
const recipientAddress = process.env.NANO_ADDRESS;
const redirectUrl = process.env.REDIRECT_URL;
try {
const response = await fetch("https://nanopay.me/api/invoices", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${API_TOKEN}`
},
body: JSON.stringify({
title: `Tip from ${username}`,
description: `Sending tip to ${streamchannel}`,
price: parseFloat(amount),
recipient_address: recipientAddress,
metadata: { username, message },
redirect_url: redirectUrl
})
});
const data = await response.json();
console.log("NanoPay API Response:", data);
if (data.pay_url) {
res.json({ payment_url: data.pay_url });
} else {
res.status(400).json({ error: "Failed to create invoice", details: data });
}
} catch (error) {
console.error("Error creating invoice:", error);
res.status(500).json({ error: "Server error" });
}
});
// Webhook Endpoint
app.post("/nanopay-webhook", async (req, res) => {
console.log("🔥 Full NanoPay Webhook Data:", JSON.stringify(req.body, null, 2));
const { type, invoice, payment } = req.body;
const status = invoice?.status;
const amount_received = payment?.amount;
const metadata = invoice?.metadata;
if (!status) {
console.warn("⚠️ Webhook received, but 'status' is missing.");
return res.sendStatus(400);
}
if (status !== "paid" && status !== "pending") {
console.warn(`⚠️ Webhook received, but status is '${status}', not 'paid' or 'pending'.`);
return res.sendStatus(200);
}
if (!metadata?.username) {
console.warn("⚠️ Webhook received, but missing metadata.username");
return res.sendStatus(400);
}
const username = metadata.username;
const message = metadata.message || "No message";
const amount = parseFloat(amount_received);
console.log(`✅ Payment received from ${username}: ${amount} XNO`);
await sendStreamerBotAlert(username, message, amount);
res.sendStatus(200);
});
// Send alert to Streamer.bot
async function sendStreamerBotAlert(username, message, amount) {
const exchangeRate = await getNanoToUsdRate();
const amountInUsd = (amount * exchangeRate).toFixed(2);
try {
const response = await fetch(`${process.env.STREAMERBOT_URL}/DoAction`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
action: {
id: process.env.STREAMERBOT_ACTION_ID,
name: process.env.STREAMERBOT_ACTION_NAME
},
args: {
tipName: username,
tipAmount: String(amount),
tipAmountUsd: amountInUsd,
tipMessage: message
}
})
});
if (response.status === 204) {
console.log(`✅ Streamer.bot action triggered for ${username}: ${amount} XNO (~$${amountInUsd} USD)`);
} else {
console.error("❌ Streamer.bot error:", response.status, await response.text());
}
} catch (error) {
console.error("❌ Error contacting Streamer.bot:", error);
}
}
// Get current Nano (XNO) to USD exchange rate
async function getNanoToUsdRate() {
try {
const response = await fetch(`https://api.coingecko.com/api/v3/simple/price?ids=nano&vs_currencies=usd&x_cg_demo_api_key=${process.env.COINGECKO_API_KEY}`);
const data = await response.json();
if (data.nano?.usd) {
console.log(`✅ Nano price: $${data.nano.usd}`);
return data.nano.usd;
}
throw new Error("No price in response: " + JSON.stringify(data));
} catch (error) {
console.error("❌ Failed to get Nano price:", error);
return 5.00; // fallback rate
}
}
// Start the server
app.get("/", (req, res) => {
res.send("🚀 Server is running!");
});
app.listen(PORT, () => console.log(`🚀 Server running on port ${PORT}`));