ipfs storage for images and other nontext items. for use with etica - runs on etica network and currencys
https://collect.etica-stats.org
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
82 lines
2.1 KiB
82 lines
2.1 KiB
// /home/def/IPFSapp/backend/expire.js |
|
// Unpins CIDs whose payments.expires_at < now(); marks status='expired'. |
|
// Uses the same .env as server.js (dotenv). |
|
|
|
import 'dotenv/config'; |
|
import { Pool } from 'pg'; |
|
|
|
const { |
|
DATABASE_URL, |
|
IPFS_API = 'http://127.0.0.1:5001/api/v0' |
|
} = process.env; |
|
|
|
if (!DATABASE_URL) { |
|
console.error('Missing DATABASE_URL'); |
|
process.exit(1); |
|
} |
|
|
|
const pool = new Pool({ connectionString: DATABASE_URL }); |
|
const sql = (q, p=[]) => pool.query(q, p); |
|
|
|
const nowIso = () => new Date().toISOString(); |
|
|
|
async function fetchJSON(url, opts = {}) { |
|
const r = await fetch(url, opts); |
|
if (!r.ok) throw new Error(`${url} → ${r.status}`); |
|
try { return await r.json(); } catch { return {}; } |
|
} |
|
|
|
async function unpinCid(cid) { |
|
// POST /api/v0/pin/rm?arg=<cid>&recursive=true |
|
const url = `${IPFS_API}/pin/rm?arg=${encodeURIComponent(cid)}&recursive=true`; |
|
await fetchJSON(url, { method: 'POST' }); |
|
} |
|
|
|
async function gcRepo() { |
|
// Trigger a GC pass (optional; Kubo also GC’s with --enable-gc) |
|
try { await fetchJSON(`${IPFS_API}/repo/gc`, { method: 'POST' }); } catch {} |
|
} |
|
|
|
async function run() { |
|
console.log(`[expirer] start ${nowIso()}`); |
|
|
|
// pick up items with expired retention that are still considered kept |
|
const { rows } = await sql(` |
|
SELECT quote_id, cid |
|
FROM payments |
|
WHERE cid IS NOT NULL |
|
AND expires_at IS NOT NULL |
|
AND expires_at < now() |
|
AND status IN ('paid','confirmed') |
|
ORDER BY expires_at ASC |
|
LIMIT 500 |
|
`); |
|
|
|
if (!rows.length) { |
|
console.log('[expirer] nothing to expire'); |
|
process.exit(0); |
|
} |
|
|
|
let ok = 0, fail = 0; |
|
for (const r of rows) { |
|
try { |
|
await unpinCid(r.cid); |
|
await sql(`UPDATE payments SET status='expired' WHERE quote_id=$1`, [r.quote_id]); |
|
console.log(`[expirer] expired ${r.cid} (quote ${r.quote_id})`); |
|
ok++; |
|
} catch (e) { |
|
console.error(`[expirer] failed ${r.cid}: ${e.message || e}`); |
|
fail++; |
|
} |
|
} |
|
|
|
await gcRepo(); |
|
|
|
console.log(`[expirer] done ok=${ok} fail=${fail} ${nowIso()}`); |
|
process.exit(0); |
|
} |
|
|
|
run().catch(e => { |
|
console.error('[expirer] fatal', e); |
|
process.exit(1); |
|
});
|
|
|