Hello world
This commit is contained in:
159
index.js
Normal file
159
index.js
Normal file
@@ -0,0 +1,159 @@
|
||||
import { client, xml } from "@xmpp/client";
|
||||
// import debug from "@xmpp/debug";
|
||||
import config from "./config.js";
|
||||
import Lndhub from "./lib/lndhub.js";
|
||||
import {
|
||||
randomHex,
|
||||
pingXml,
|
||||
isPingResponse,
|
||||
roomDirectMessageXml,
|
||||
grantVoiceMessageXml,
|
||||
parseForm,
|
||||
isVoiceRequest,
|
||||
} from "./lib/utils.js";
|
||||
|
||||
const xmpp = client(config.xmpp);
|
||||
|
||||
// debug(xmpp, true);
|
||||
|
||||
const connectRetryInMilliseconds = 5000;
|
||||
const pingIntervalInMilliseconds = 3000;
|
||||
const pingTimeoutInMilliseconds = 10000;
|
||||
let pingInterval = null;
|
||||
let lastPingSuccess = null;
|
||||
|
||||
const lndhub = new Lndhub(config.lndhub.endpoint);
|
||||
|
||||
function checkAndSendPing () {
|
||||
const now = new Date();
|
||||
if ((now.getTime() - lastPingSuccess.getTime()) > pingTimeoutInMilliseconds) {
|
||||
console.log(`No ping response received in ${pingTimeoutInMilliseconds/1000} seconds, reconnecting`);
|
||||
clearInterval(pingInterval);
|
||||
xmpp.stop().catch(console.error);
|
||||
} else {
|
||||
xmpp.send(pingXml(config.xmpp.service))
|
||||
.catch(err => console.warn(err));
|
||||
}
|
||||
}
|
||||
|
||||
function startPingInterval () {
|
||||
if (pingInterval) { clearInterval(pingInterval); }
|
||||
pingInterval = setInterval(checkAndSendPing, pingIntervalInMilliseconds);
|
||||
}
|
||||
|
||||
function waitForInvoicePaid (room, nick, invoice, retries=0) {
|
||||
if (retries >= 300) {
|
||||
console.log(`Invoice not paid after 15 minutes: ${invoice.payment_hash}`);
|
||||
return false;
|
||||
}
|
||||
lndhub.getInvoice(invoice.payment_hash).then(async data => {
|
||||
if (data.is_paid) {
|
||||
console.log(`Invoice paid: ${invoice.payment_hash}`);
|
||||
await grantVoice(room, nick);
|
||||
} else {
|
||||
setTimeout(waitForInvoicePaid, 3000, room, nick, invoice, retries++);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function respondToVoiceRequest (room, nick, invoice) {
|
||||
const welcomeMessage = `
|
||||
Welcome, ${nick}! I see you're interested in joining the conversation.
|
||||
|
||||
You can wait for a human moderator to approve your request, but it may take a while. You may also prove that you're not a spambot by donating a small amount of sats for the maintenance of this chat server via the following Lightning invoice. I will immediately approve your request in that case.
|
||||
|
||||
${invoice.payment_request}
|
||||
`;
|
||||
|
||||
await xmpp.send(roomDirectMessageXml(room, nick, welcomeMessage));
|
||||
}
|
||||
|
||||
async function grantVoice (room, nick) {
|
||||
console.log(`Granting voice to ${nick} in ${room}`);
|
||||
await xmpp.send(grantVoiceMessageXml(room, nick));
|
||||
|
||||
const message = `Thanks ${nick}, and welcome aboard! You can send messages to the channel now.`;
|
||||
await xmpp.send(roomDirectMessageXml(room, nick, message));
|
||||
}
|
||||
|
||||
async function handleVoiceRequest (stanza) {
|
||||
try {
|
||||
const formFields = parseForm(stanza);
|
||||
const room = stanza.attrs.from;
|
||||
// const jid = formFields.find(f => f.name === "muc#jid").value;
|
||||
const nick = formFields.find(f => f.name === "muc#roomnick").value;
|
||||
console.log(`${nick} requested voice in ${room}`);
|
||||
|
||||
const invoice = await lndhub.createInvoice(config.amounts.voice, `Donation for ${room}`);
|
||||
console.log(`Created lightning invoice for ${nick}: ${invoice.payment_hash}`)
|
||||
|
||||
await respondToVoiceRequest(room, nick, invoice);
|
||||
waitForInvoicePaid(room, nick, invoice);
|
||||
} catch(err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
async function connectXmpp () {
|
||||
await xmpp.start().catch(err => {
|
||||
console.log(`Connect error: ${err}`);
|
||||
console.log(`Retrying in ${connectRetryInMilliseconds/1000} seconds`);
|
||||
setTimeout(async () => {
|
||||
await connectXmpp();
|
||||
}, connectRetryInMilliseconds);
|
||||
});
|
||||
}
|
||||
|
||||
function connectLndhub () {
|
||||
return lndhub.auth(config.lndhub.username, config.lndhub.password).then(() => {
|
||||
console.log("Connected to Lndhub");
|
||||
}).catch(err => {
|
||||
console.warn(`Lndhub auth failed: ${err}`);
|
||||
});
|
||||
}
|
||||
|
||||
function handlePingResponse (stanza) {
|
||||
lastPingSuccess = new Date();
|
||||
}
|
||||
|
||||
function readIq (stanza) {
|
||||
if (isPingResponse(stanza)) handlePingResponse(stanza);
|
||||
}
|
||||
|
||||
function readMessage (stanza) {
|
||||
if (isVoiceRequest(stanza)) handleVoiceRequest(stanza);
|
||||
}
|
||||
|
||||
xmpp.on("error", (err) => {
|
||||
console.error(err);
|
||||
});
|
||||
|
||||
xmpp.on("offline", () => {
|
||||
console.log("Offline");
|
||||
connectXmpp();
|
||||
});
|
||||
|
||||
xmpp.on("online", async (address) => {
|
||||
console.log("Connected to XMPP server");
|
||||
|
||||
for (const jid of config.xmpp.rooms) {
|
||||
const msg = xml("presence", { to: `${jid}/${config.nick}` });
|
||||
await xmpp.send(msg);
|
||||
}
|
||||
|
||||
connectLndhub();
|
||||
|
||||
lastPingSuccess = new Date();
|
||||
startPingInterval();
|
||||
});
|
||||
|
||||
xmpp.on("stanza", async (stanza) => {
|
||||
if (stanza.is("iq")) readIq(stanza);
|
||||
if (stanza.is("message")) readMessage(stanza);
|
||||
});
|
||||
|
||||
xmpp.on("status", (status) => {
|
||||
console.debug("XMPP status:", status);
|
||||
});
|
||||
|
||||
connectXmpp();
|
||||
Reference in New Issue
Block a user