From 675d326f3b2526d239b925e228c58c3629f02de5 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Wed, 30 Aug 2023 16:37:29 +0000 Subject: netherlands euro --- lib/countries.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/countries.js b/lib/countries.js index ad049fba..9220a886 100644 --- a/lib/countries.js +++ b/lib/countries.js @@ -151,7 +151,7 @@ export default { NA: "NAM", NR: "NRU", NP: "NPL", - NL: "NLD", + NL: "EUR", AN: "ANG", NC: "XPF", NZ: "NZD", -- cgit v1.2.3 From cb9d32933482ccca080786697c718266023faf5b Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Mon, 28 Aug 2023 06:33:22 +0000 Subject: wip --- lib/payments.js | 39 ++++++++++++++++++++++++++++++++++++++- routes/payments.js | 4 ++++ 2 files changed, 42 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/payments.js b/lib/payments.js index 9172c794..6a2d5ec1 100644 --- a/lib/payments.js +++ b/lib/payments.js @@ -190,10 +190,39 @@ export let credit = async (hash, amount, memo, ref, type = types.internal) => { let connected; let f = fs.createWriteStream(out); + client.subscribe(username); + mimic.stdout.on("end", async () => { await wait(() => connected); client.publish(username, "start"); + let n = 0; + + let sentChunks = {}; // Dictionary to store chunks and their respective sequence numbers. + + function retransmit(chunkNumber) { + if(sentChunks[chunkNumber]){ + console.log("retransmitting", chunkNumber) + client.publish(username, chunkNumber.toString()); + client.publish(username, sentChunks[chunkNumber]); + setTimeout(() => { + if (sentChunks[chunkNumber]) { // Retransmit if not acknowledged + retransmit(chunkNumber); + } + }, 5000); // Check for retransmission every 5 seconds + } + } + + client.on('message', (topic, message) => { + if (message.length < 20) console.log(message, message.toString()); + if (topic === username && message.toString().startsWith('ack:')) { + let seqNumber = parseInt(message.split(':')[1]); + console.log("ACK", seqNumber); + delete sentChunks[seqNumber]; // Remove acknowledged chunk from dictionary + if (!Object.keys(sentChunks).length) client.publish(username, "end"); + } + }); + ffmpeg(raw) .audioBitrate(128) .audioFrequency(44100) @@ -203,13 +232,21 @@ export let credit = async (hash, amount, memo, ref, type = types.internal) => { }) .stream() .on('data', (chunk) => { + let seq = n; + client.publish(username, n.toString()); + sentChunks[n] = chunk; client.publish(username, chunk); f.write(chunk); + setTimeout(() => { + if (sentChunks[seq]) { // Retransmit if not acknowledged + retransmit(seq); + } + }, 5000); + n++; }) .on('end', () => { console.log("FFMPEG done"); f.end(); - client.publish(username, "end"); }); }); diff --git a/routes/payments.js b/routes/payments.js index 425561f1..c13f7bec 100644 --- a/routes/payments.js +++ b/routes/payments.js @@ -232,6 +232,7 @@ export default { }, async take({ body: { name, amount, hash }, user }, res) { + try { amount = parseInt(amount); if (amount < 0) fail("Invalid amount"); @@ -258,6 +259,9 @@ export default { await db.lPush(`pot:${name}:payments`, hash); res.send({ payment }); + } catch(e) { + bail(res, e.message); + } }, async bitcoin({ body: { txid, wallet } }, res) { -- cgit v1.2.3 From 7945e4db0d3f4d1b298beee13c842a47354603e6 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Fri, 1 Sep 2023 22:30:51 -0700 Subject: send missing chunks --- lib/payments.js | 117 +++++++++++++++++++++++++++++++------------------------- package.json | 1 + pnpm-lock.yaml | 7 ++++ 3 files changed, 73 insertions(+), 52 deletions(-) (limited to 'lib') diff --git a/lib/payments.js b/lib/payments.js index 6a2d5ec1..ad877290 100644 --- a/lib/payments.js +++ b/lib/payments.js @@ -11,8 +11,10 @@ import dollarsToWords from "dollars-to-words"; import got from "got"; import mqtt from "mqtt"; import { spawn } from "child_process"; -import ffmpeg from 'fluent-ffmpeg'; +import ffmpeg from "fluent-ffmpeg"; import fs from "fs"; +import EventEmitter from "events"; +import crc32 from "buffer-crc32"; export const types = { internal: "internal", @@ -183,12 +185,18 @@ export let credit = async (hash, amount, memo, ref, type = types.internal) => { parseFloat(((amount * p.rate) / 100000000).toFixed(2)) ); - const client = mqtt.connect('mqtt://ln.coinos.io', config.mqtt); + const client = mqtt.connect("mqtt://ln.coinos.io", config.mqtt); const raw = `/app/data/uploads/${p.id}-raw.mp3`; const out = `/app/data/uploads/${p.id}.mp3`; - const mimic = spawn("/mimic", ["-t", words, "-voice", "/cmu_us_axb.flitevox", "-o", raw]); + const mimic = spawn("/mimic", [ + "-t", + words, + "-voice", + "/cmu_us_axb.flitevox", + "-o", + raw + ]); let connected; - let f = fs.createWriteStream(out); client.subscribe(username); @@ -197,61 +205,66 @@ export let credit = async (hash, amount, memo, ref, type = types.internal) => { client.publish(username, "start"); let n = 0; + let t = 0; + let sz = 480; + let chunks = []; + let buf = Buffer.alloc(0); - let sentChunks = {}; // Dictionary to store chunks and their respective sequence numbers. - - function retransmit(chunkNumber) { - if(sentChunks[chunkNumber]){ - console.log("retransmitting", chunkNumber) - client.publish(username, chunkNumber.toString()); - client.publish(username, sentChunks[chunkNumber]); - setTimeout(() => { - if (sentChunks[chunkNumber]) { // Retransmit if not acknowledged - retransmit(chunkNumber); - } - }, 5000); // Check for retransmission every 5 seconds - } - } - - client.on('message', (topic, message) => { - if (message.length < 20) console.log(message, message.toString()); - if (topic === username && message.toString().startsWith('ack:')) { - let seqNumber = parseInt(message.split(':')[1]); - console.log("ACK", seqNumber); - delete sentChunks[seqNumber]; // Remove acknowledged chunk from dictionary - if (!Object.keys(sentChunks).length) client.publish(username, "end"); + let send = n => { + let chunk = chunks[n]; + if (!chunk) return; + + let num = Buffer.alloc(2); + num.writeUInt16BE(n, 0); + + let flag = Buffer.from("dddddddd", "hex"); + let checksum = crc32(chunk).reverse(); + + let payload = Buffer.concat([flag, num, checksum, chunk]); + client.publish(username, payload); + }; + + client.on("message", (topic, message) => { + if (topic !== username) return; + let m = message.toString(); + if (m.startsWith("missing:")) { + let missing = m.replace("missing:", "").split(","); + + for (let n of missing) send(chunk); + client.publish(username, `end:${n}`); } - }); ffmpeg(raw) - .audioBitrate(128) - .audioFrequency(44100) - .toFormat('mp3') - .on('error', (err) => { - console.log('Error:', err); - }) - .stream() - .on('data', (chunk) => { - let seq = n; - client.publish(username, n.toString()); - sentChunks[n] = chunk; - client.publish(username, chunk); - f.write(chunk); - setTimeout(() => { - if (sentChunks[seq]) { // Retransmit if not acknowledged - retransmit(seq); - } - }, 5000); + .audioBitrate(128) + .audioFrequency(44100) + .toFormat("mp3") + .on("error", err => { + console.log("Error:", err); + }) + .stream() + .on("data", data => { + t += data.length; + let i = 0; + buf = Buffer.concat([buf, data]); + + while (i < data.length) { + chunks[n] = data.slice(i, i + sz); + send(n); + n++; - }) - .on('end', () => { - console.log("FFMPEG done"); - f.end(); - }); + i += sz; + } + }) + .on("end", () => { + client.publish(username, `end:${chunks.length}`); + }); }); - client.on('connect', function () { - client.publish(username, `${p.amount}:${p.tip}:${p.rate}:${p.created}:${p.id}`); + client.on("connect", function() { + client.publish( + username, + `pay:${p.amount}:${p.tip}:${p.rate}:${p.created}:${p.id}` + ); setTimeout(() => (connected = true), 50); }); } diff --git a/package.json b/package.json index f617d2a8..d7d97c3d 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "@fastify/websocket": "^7.2.0", "bcrypt": "^5.0.0", "bech32": "^2.0.0", + "buffer-crc32": "^0.2.13", "clightning-client": "github:SimonVrouwe/lightning-client-js#2022-11-04_improve_doc", "date-fns": "^2.21.3", "dollars-to-words": "github:asoltys/dollars-to-words", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a5b398a1..4a1ad2b3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -32,6 +32,9 @@ dependencies: bech32: specifier: ^2.0.0 version: 2.0.0 + buffer-crc32: + specifier: ^0.2.13 + version: 0.2.13 clightning-client: specifier: github:SimonVrouwe/lightning-client-js#2022-11-04_improve_doc version: github.com/SimonVrouwe/lightning-client-js/946642bafca572fb5d9ce2dc1316d415fa950a05 @@ -1376,6 +1379,10 @@ packages: safe-buffer: 5.2.1 dev: false + /buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + dev: false + /buffer-equal-constant-time@1.0.1: resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} dev: false -- cgit v1.2.3 From 8d19a2ab496770856a6780c553c7eae350bc3494 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Fri, 1 Sep 2023 22:34:35 -0700 Subject: missing braces --- lib/payments.js | 1 + 1 file changed, 1 insertion(+) (limited to 'lib') diff --git a/lib/payments.js b/lib/payments.js index ad877290..72beaac6 100644 --- a/lib/payments.js +++ b/lib/payments.js @@ -267,6 +267,7 @@ export let credit = async (hash, amount, memo, ref, type = types.internal) => { ); setTimeout(() => (connected = true), 50); }); + }); } return p; -- cgit v1.2.3 From 68a2aede36519b4d5891c9427e5cddc699082189 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Fri, 1 Sep 2023 22:42:31 -0700 Subject: cleanup --- lib/payments.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'lib') diff --git a/lib/payments.js b/lib/payments.js index 72beaac6..c8e74201 100644 --- a/lib/payments.js +++ b/lib/payments.js @@ -185,10 +185,14 @@ export let credit = async (hash, amount, memo, ref, type = types.internal) => { parseFloat(((amount * p.rate) / 100000000).toFixed(2)) ); - const client = mqtt.connect("mqtt://ln.coinos.io", config.mqtt); - const raw = `/app/data/uploads/${p.id}-raw.mp3`; - const out = `/app/data/uploads/${p.id}.mp3`; - const mimic = spawn("/mimic", [ + let client = mqtt.connect("mqtt://ln.coinos.io", config.mqtt); + client.subscribe(username); + + let raw = `/app/data/uploads/${p.id}-raw.mp3`; + let out = `/app/data/uploads/${p.id}.mp3`; + + let connected; + let mimic = spawn("/mimic", [ "-t", words, "-voice", @@ -196,9 +200,6 @@ export let credit = async (hash, amount, memo, ref, type = types.internal) => { "-o", raw ]); - let connected; - - client.subscribe(username); mimic.stdout.on("end", async () => { await wait(() => connected); @@ -233,6 +234,7 @@ export let credit = async (hash, amount, memo, ref, type = types.internal) => { for (let n of missing) send(chunk); client.publish(username, `end:${n}`); } + }); ffmpeg(raw) .audioBitrate(128) @@ -267,7 +269,6 @@ export let credit = async (hash, amount, memo, ref, type = types.internal) => { ); setTimeout(() => (connected = true), 50); }); - }); } return p; -- cgit v1.2.3 From 0d7574597d33bad78f4ebad3c38b956debb0e699 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sat, 2 Sep 2023 17:12:10 +0000 Subject: fix swedish currency --- lib/countries.js | 2 +- lib/payments.js | 21 ++++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'lib') diff --git a/lib/countries.js b/lib/countries.js index 9220a886..5fc19683 100644 --- a/lib/countries.js +++ b/lib/countries.js @@ -213,7 +213,7 @@ export default { SR: "SUR", SJ: "NOK", SZ: "SWZ", - SE: "SWE", + SE: "SEK", CH: "CHE", SY: "SYR", TW: "TWN", diff --git a/lib/payments.js b/lib/payments.js index c8e74201..2764df18 100644 --- a/lib/payments.js +++ b/lib/payments.js @@ -181,13 +181,28 @@ export let credit = async (hash, amount, memo, ref, type = types.internal) => { callWebhook(invoice, p); if (user.hasprinter) { - let words = dollarsToWords( - parseFloat(((amount * p.rate) / 100000000).toFixed(2)) - ); + let fiat = parseFloat(((amount * p.rate) / 100000000).toFixed(2)); + let words = dollarsToWords(fiat); let client = mqtt.connect("mqtt://ln.coinos.io", config.mqtt); client.subscribe(username); + if (fiat === 0.02) { + words = "there is no second best"; + client.publish(username, "easter"); + } + + if (fiat === 0.21) { + words = "tick tock, next block"; + client.publish(username, "easter"); + } + + if (fiat === 0.69) { + words = "have fun staying poor"; + client.publish(username, "easter"); + } + + let raw = `/app/data/uploads/${p.id}-raw.mp3`; let out = `/app/data/uploads/${p.id}.mp3`; -- cgit v1.2.3 From 3aa200db295438827bfff48f80e3f4b25f44e8ea Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Sun, 3 Sep 2023 20:48:31 -0700 Subject: use bolt11 for invoice hash --- lib/invoices.js | 20 ++++++++------------ lib/lightning.js | 9 ++++----- routes/invoices.js | 4 ---- routes/payments.js | 9 +++++---- 4 files changed, 17 insertions(+), 25 deletions(-) (limited to 'lib') diff --git a/lib/invoices.js b/lib/invoices.js index b4583ea1..2e5a8e64 100644 --- a/lib/invoices.js +++ b/lib/invoices.js @@ -38,19 +38,15 @@ export let generate = async ({ invoice, user, sender, memo }) => { let hash, text; if (type === types.lightning) { - let r = await ln.invoice( - amount ? `${amount + tip}sat` : "any", - new Date(), - memo || "", - expiry || 3600, - undefined, - undefined, - undefined, - undefined, - true - ); + let r = await ln.invoice({ + amount_msat: amount ? `${amount + tip}sat` : "any", + label: new Date(), + description: memo || "", + expiry: expiry || 3600, + deschashonly: true + }); - hash = r.payment_hash; + hash = r.bolt11; text = r.bolt11; } else if (type === types.bitcoin) { hash = await bc.getNewAddress(); diff --git a/lib/lightning.js b/lib/lightning.js index 1ccdbaa4..0c5fd75e 100644 --- a/lib/lightning.js +++ b/lib/lightning.js @@ -10,7 +10,6 @@ import { credit, types } from "$lib/payments"; export async function listenForLightning() { let event = await ln.waitanyinvoice(await g("pay_index")); let { - payment_hash: hash, bolt11, pay_index, status, @@ -28,13 +27,13 @@ export async function listenForLightning() { if (!preimage) return; - let invoice = await g(`invoice:${hash}`); + let invoice = await g(`invoice:${bolt11}`); if (!invoice) return warn("received lightning with no invoice", bolt11); - let payment = await g(`payment:${hash}`); - if (payment) return warn("already processed", hash); + let payment = await g(`payment:${bolt11}`); + if (payment) return warn("already processed", bolt11); - await credit(hash, received, invoice.memo, preimage, types.lightning); + await credit(bolt11, received, invoice.memo, preimage, types.lightning); } catch (e) { console.log(e); err("problem receiving lightning payment", e.message); diff --git a/routes/invoices.js b/routes/invoices.js index a1ead582..9f2e4c99 100644 --- a/routes/invoices.js +++ b/routes/invoices.js @@ -9,10 +9,6 @@ import ln from "$lib/ln"; export default { async get({ params: { hash } }, res) { let pr; - if (hash.startsWith("ln")) { - ({ payment_hash: hash } = await ln.decode(hash)); - } - let invoice = await g(`invoice:${hash}`); if (invoice) { diff --git a/routes/payments.js b/routes/payments.js index c13f7bec..383b89fc 100644 --- a/routes/payments.js +++ b/routes/payments.js @@ -61,11 +61,11 @@ export default { let total = amount; let { amount_msat, payment_hash } = await ln.decode(payreq); if (amount_msat) total = Math.round(amount_msat / 1000); - let invoice = await g(`invoice:${payment_hash}`); + let invoice = await g(`invoice:${payreq}`); if (invoice) { if (invoice.uid === user.id) fail("Cannot send to self"); - hash = payment_hash; + hash = payreq; } else { p = await debit(hash, total, maxfee, memo, user, types.lightning); @@ -79,7 +79,8 @@ export default { maxfee: maxfee * 1000, retry_for: 5 }); - if (r.status !== "complete") fail("payment did not complete"); + + if (r.status !== "complete" || !r.payment_preimage) fail("payment did not complete"); p.amount = -amount; p.tip = total - amount; @@ -93,7 +94,7 @@ export default { await db.incrBy(`balance:${p.uid}`, maxfee - p.fee); } catch (e) { warn("something went wrong", e.message); - if (!(r && r.status === "complete")) { + if (!(r && r.status === "complete" && r.payment_preimage)) { let credit = Math.round(total * config.fee) - p.ourfee; warn("crediting balance", total + maxfee + p.ourfee); await db.incrBy(`balance:${p.uid}`, total + maxfee + p.ourfee); -- cgit v1.2.3