fix(gowa): QR sebagai data URI + rewrite qr_link ke base URL publik
All checks were successful
CI / test (push) Successful in 2m41s
All checks were successful
CI / test (push) Successful in 2m41s
- gambar tidak lagi bergantung request /qr.png kedua - qr_link host internal diganti origin base URL - log saat gambar gagal diambil; onerror di UI - versi 0.5.9
This commit is contained in:
@@ -2,6 +2,13 @@
|
||||
|
||||
Format mengikuti [Keep a Changelog](https://keepachangelog.com/) dan [Semantic Versioning](https://semver.org/).
|
||||
|
||||
## [0.5.9] — 2026-11-05 — "gowa-qr-image"
|
||||
|
||||
### Diperbaiki
|
||||
- QR GOWA dikirim sebagai **data URI** sehingga gambar tetap tampil walau app berjalan multi-proses atau request gambar terpisah gagal.
|
||||
- `qr_link` dari GOWA yang menunjuk host internal (`127.0.0.1`/container) ditulis ulang memakai base URL publik yang dikonfigurasi.
|
||||
- Log peringatan `[GOWA] Gagal ambil gambar QR` bila pengambilan gambar gagal.
|
||||
|
||||
## [0.5.8] — 2026-11-05 — "gowa-qr-error"
|
||||
|
||||
### Diperbaiki
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
<p align="center">
|
||||
<img src="https://img.shields.io/badge/lisensi-ISC-ADFF2F" alt="Lisensi: ISC">
|
||||
<img src="https://img.shields.io/badge/versi-0.5.8_gowa--qr-error-ADFF2F" alt="Versi 0.5.8 (gowa-qr-error)">
|
||||
<img src="https://img.shields.io/badge/versi-0.5.9_gowa--qr-image-ADFF2F" alt="Versi 0.5.9 (gowa-qr-image)">
|
||||
<img src="https://img.shields.io/badge/Node.js-%E2%89%A520-339933" alt="Node.js >= 20">
|
||||
<img src="https://img.shields.io/badge/docker-ready-2496ED?logo=docker&logoColor=white" alt="Docker">
|
||||
<a href="https://demo-openisp.oxpoe.xyz"><img src="https://img.shields.io/badge/demo-live-ADFF2F?logo=googlechrome&logoColor=black" alt="Demo"></a>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "open-isp",
|
||||
"version": "0.5.8",
|
||||
"version": "0.5.9",
|
||||
"description": "OPEN-ISP \u2014 sistem billing & manajemen ISP open-source (PWA pelanggan, multi-OLT, RADIUS, WhatsApp, QRIS)",
|
||||
"main": "app-customer.js",
|
||||
"scripts": {
|
||||
|
||||
@@ -6654,7 +6654,16 @@ router.get('/whatsapp/gowa/qr', requireAdminSession, async (req, res) => {
|
||||
const detail = r.message || r.code || 'pastikan GOWA berjalan & username/password Basic Auth benar';
|
||||
return res.json({ ok: false, status: r.status || 0, message: 'Gagal membuat QR: ' + (r.status ? 'HTTP ' + r.status + ' — ' : '') + detail + '.' });
|
||||
}
|
||||
return res.json({ ok: true, image: '/admin/whatsapp/gowa/qr.png?v=' + Date.now(), device_id: r.device_id, duration: r.duration });
|
||||
// Kirim gambar langsung sebagai data URI: tidak bergantung pada request
|
||||
// kedua /qr.png (aman bila app berjalan multi-proses) dan tidak kena cache.
|
||||
let image = '/admin/whatsapp/gowa/qr.png?v=' + Date.now();
|
||||
try {
|
||||
const img = await gowa.getLastQrImage();
|
||||
if (img && img.buffer && img.buffer.length) {
|
||||
image = 'data:' + (img.contentType || 'image/png') + ';base64,' + img.buffer.toString('base64');
|
||||
}
|
||||
} catch (e) {}
|
||||
return res.json({ ok: true, image, device_id: r.device_id, duration: r.duration });
|
||||
} catch (e) { return res.json({ ok: false, message: e.message }); }
|
||||
});
|
||||
|
||||
|
||||
@@ -192,14 +192,37 @@ async function getLoginQr(deviceId) {
|
||||
return { ok: false, status: 0, code: null, message: e.message };
|
||||
}
|
||||
}
|
||||
// GOWA bisa mengembalikan qr_link absolut ke host internal (127.0.0.1 / nama
|
||||
// container). Ambil path-nya saja lalu tempel ke base URL yang dikonfigurasi,
|
||||
// supaya gambar tetap bisa diambil saat GOWA diakses lewat domain/reverse proxy.
|
||||
function resolveQrLink(link) {
|
||||
const l = String(link || '').trim();
|
||||
if (!l) return '';
|
||||
if (/^data:/i.test(l)) return l;
|
||||
try {
|
||||
const u = new URL(l, baseUrl() + '/');
|
||||
const base = new URL(baseUrl());
|
||||
return base.origin + u.pathname + u.search;
|
||||
} catch (e) {
|
||||
return baseUrl() + (l.charAt(0) === '/' ? l : '/' + l);
|
||||
}
|
||||
}
|
||||
|
||||
async function getLastQrImage() {
|
||||
if (!_lastQr.link) return null;
|
||||
const url = resolveQrLink(_lastQr.link);
|
||||
try {
|
||||
const res = await fetch(_lastQr.link, { headers: commonHeaders() });
|
||||
if (!res.ok) return null;
|
||||
const res = await fetch(url, { headers: commonHeaders() });
|
||||
if (!res.ok) {
|
||||
logger.warn(`[GOWA] Gagal ambil gambar QR: HTTP ${res.status} (${url})`);
|
||||
return null;
|
||||
}
|
||||
const buf = Buffer.from(await res.arrayBuffer());
|
||||
return { buffer: buf, contentType: res.headers.get('content-type') || 'image/png' };
|
||||
} catch (e) { return null; }
|
||||
} catch (e) {
|
||||
logger.warn(`[GOWA] Gagal ambil gambar QR: ${e.message} (${url})`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { sendGowaMessage, sendGowaImage, sendGowaDocument, testGowaConnection, gowaStatus, listDevices, ensureDevice, getLoginQr, getLastQrImage, normalizePhoneJid, baseUrl, resolveDeviceId, invalidateDeviceCache };
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.5.8
|
||||
0.5.9
|
||||
@@ -181,7 +181,7 @@
|
||||
<button type="button" class="btn btn-p btn-sm" onclick="showGowaQr()"><i class="bi bi-qr-code-scan"></i> Tampilkan QR</button>
|
||||
<a href="<%= gowaUiUrl %>" target="_blank" rel="noopener" class="btn btn-g btn-sm" style="margin-left:6px"><i class="bi bi-box-arrow-up-right"></i> Buka UI GOWA</a>
|
||||
<div id="gowa_qr_wrap" style="display:none;margin-top:10px;text-align:center">
|
||||
<img id="gowa_qr_img" alt="QR GOWA" style="max-width:240px;background:#fff;padding:10px;border-radius:12px">
|
||||
<img id="gowa_qr_img" alt="QR GOWA" style="max-width:240px;background:#fff;padding:10px;border-radius:12px" onerror="var s=document.getElementById('gowa_qr_status');if(s)s.textContent='Gambar QR gagal dimuat — cek log server (base URL/kredensial GOWA).'">
|
||||
<div id="gowa_qr_status" style="font-size:12px;color:var(--muted);margin-top:6px"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user