100 lines
4.2 KiB
JavaScript
100 lines
4.2 KiB
JavaScript
// ═══════════════════════════════════════════════════════════════════════════════
|
|||
|
|
// Waar staat de relay, en waar mogen de gegevens staan.
|
||
|
|
//
|
||
|
|
// Het adres van de Umbrel staat NIET in deze repo en hoort daar ook niet in:
|
||
|
|
// dit is een publieke app store, en de .gitignore van de repo-root heeft er een
|
||
|
|
// eigen kopje over. Het komt dus uit de omgeving, met `.env` als de gewone weg
|
||
|
|
// en `.env.sample` als het voorbeeld dat wél in de repo staat.
|
||
|
|
//
|
||
|
|
// Geen dotenv-pakket: dat is een afhankelijkheid voor twintig regels, en die
|
||
|
|
// twintig regels zijn hier beter te lezen dan de instellingen van een pakket.
|
||
|
|
// ═══════════════════════════════════════════════════════════════════════════════
|
||
|
|
|
||
|
|
import { readFileSync } from 'node:fs';
|
||
|
|
import { dirname, join, resolve } from 'node:path';
|
||
|
|
import { fileURLToPath } from 'node:url';
|
||
|
|
|
||
|
|
/** De wortel van dit gereedschap, ongeacht vanwaar het gestart wordt. */
|
||
|
|
export const WORTEL = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Leest een `.env`-bestand.
|
||
|
|
*
|
||
|
|
* Regels van de vorm `NAAM=waarde`. Lege regels en regels die met `#` beginnen
|
||
|
|
* worden overgeslagen, en aanhalingstekens om de waarde gaan eraf. Meer niet: wie
|
||
|
|
* hier een regel met een dubbele bodem in zet, krijgt hem letterlijk terug.
|
||
|
|
*/
|
||
|
|
export const leesEnvBestand = (inhoud) => {
|
||
|
|
const uit = {};
|
||
|
|
for (const regel of inhoud.split(/\r?\n/)) {
|
||
|
|
const kaal = regel.trim();
|
||
|
|
if (kaal === '' || kaal.startsWith('#')) continue;
|
||
|
|
const isGelijk = kaal.indexOf('=');
|
||
|
|
if (isGelijk <= 0) continue;
|
||
|
|
const naam = kaal.slice(0, isGelijk).trim();
|
||
|
|
let waarde = kaal.slice(isGelijk + 1).trim();
|
||
|
|
if (
|
||
|
|
(waarde.startsWith('"') && waarde.endsWith('"') && waarde.length >= 2)
|
||
|
|
|| (waarde.startsWith("'") && waarde.endsWith("'") && waarde.length >= 2)
|
||
|
|
) {
|
||
|
|
waarde = waarde.slice(1, -1);
|
||
|
|
}
|
||
|
|
uit[naam] = waarde;
|
||
|
|
}
|
||
|
|
return uit;
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Maakt van een adres een WebSocket-URL, of gooit met uitleg.
|
||
|
|
*
|
||
|
|
* De relay is een WebSocket-server, dus `ws://` of `wss://`. Een `http://` dat
|
||
|
|
* iemand uit de adresbalk plakt wordt omgezet in plaats van geweigerd: dat is
|
||
|
|
* de meest voorkomende vergissing en er is niets dubbelzinnigs aan.
|
||
|
|
*
|
||
|
|
* Wat er wél uitkomt is een adres zonder schema (`umbrel.local:3852`), en dat
|
||
|
|
* krijgt `ws://`. Zonder poort blijft het zoals het is: achter een reverse proxy
|
||
|
|
* met TLS is `wss://host` zonder poort juist de goede vorm.
|
||
|
|
*/
|
||
|
|
export const naarRelayUrl = (adres) => {
|
||
|
|
if (typeof adres !== 'string' || adres.trim() === '') {
|
||
|
|
throw new Error('Geen relay-adres. Zet RELAY_URL in .env; zie .env.sample.');
|
||
|
|
}
|
||
|
|
const kaal = adres.trim();
|
||
|
|
|
||
|
|
if (kaal.startsWith('ws://') || kaal.startsWith('wss://')) return kaal;
|
||
|
|
if (kaal.startsWith('http://')) return `ws://${kaal.slice('http://'.length)}`;
|
||
|
|
if (kaal.startsWith('https://')) return `wss://${kaal.slice('https://'.length)}`;
|
||
|
|
if (kaal.includes('://')) {
|
||
|
|
throw new Error(`"${kaal}" heeft een schema dat hier niets betekent. Gebruik ws:// of wss://.`);
|
||
|
|
}
|
||
|
|
return `ws://${kaal}`;
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
* De instellingen: eerst de omgeving, dan `.env`, dan de standaardwaarden.
|
||
|
|
*
|
||
|
|
* De omgeving wint van het bestand, zodat je één keer iets anders kunt proberen
|
||
|
|
* zonder het bestand aan te raken.
|
||
|
|
*/
|
||
|
|
export const leesConfig = ({ env = process.env, wortel = WORTEL } = {}) => {
|
||
|
|
let uitBestand = {};
|
||
|
|
try {
|
||
|
|
uitBestand = leesEnvBestand(readFileSync(join(wortel, '.env'), 'utf8'));
|
||
|
|
} catch (oorzaak) {
|
||
|
|
if (oorzaak.code !== 'ENOENT') throw oorzaak;
|
||
|
|
}
|
||
|
|
|
||
|
|
const haal = (naam) => env[naam] ?? uitBestand[naam];
|
||
|
|
|
||
|
|
const adres = haal('RELAY_URL');
|
||
|
|
|
||
|
|
return {
|
||
|
|
/** Het adres van de relay, of `null` als het er niet is. */
|
||
|
|
relayUrl: adres ? naarRelayUrl(adres) : null,
|
||
|
|
/** Waar het register en de databases staan. */
|
||
|
|
dataDir: resolve(wortel, haal('DATA_DIR') ?? 'data'),
|
||
|
|
/** De poort van het bedieningsvlak. */
|
||
|
|
uiPoort: Number.parseInt(haal('UI_PORT') ?? '4380', 10),
|
||
|
|
};
|
||
|
|
};
|