console.log('[Oasis Mobile] Node.js backend starting...'); process.env.HOME = process.env.HOME || require('path').resolve(__dirname, '..', '..'); process.env.ssb_appname = process.env.ssb_appname || 'ssb'; process.env.OASIS_MOBILE = '1'; process.env.CHLORIDE_JS = '1'; const path = require('path'); const fs = require('fs'); try { const androidInfo = JSON.parse(fs.readFileSync(path.join(__dirname, '.android.json'), 'utf8')); if (androidInfo.versionName) process.env.OASIS_ANDROID_VERSION = String(androidInfo.versionName); if (androidInfo.versionCode) process.env.OASIS_ANDROID_VERSION_CODE = String(androidInfo.versionCode); process.env.OASIS_ANDROID_INSTALLER = String(androidInfo.installer || ''); } catch (e) {} const tmpDir = path.join(process.env.HOME, 'tmp'); try { fs.mkdirSync(tmpDir, { recursive: true }); } catch (e) {} process.env.TMPDIR = tmpDir; process.env.TMP = tmpDir; process.env.TEMP = tmpDir; try { require('os').tmpdir = () => tmpDir; } catch (e) {} try { const dns = require('dns'); const net = require('net'); const servers = ['8.8.8.8', '1.1.1.1', '8.8.4.4']; const systemLookup = dns.lookup; const SYSTEM_LOOKUP_MS = 5000; try { dns.setServers(servers); } catch (e) {} try { if (dns.promises && dns.promises.setServers) dns.promises.setServers(servers); } catch (e) {} const localResolve = (hostname, family) => { if (hostname === 'localhost' || hostname === 'localhost.localdomain' || hostname === 'ip6-localhost') { return family === 6 ? { address: '::1', family: 6 } : { address: '127.0.0.1', family: 4 }; } const ipv = net.isIP(hostname); if (ipv) return { address: hostname, family: ipv }; return null; }; const safeLookup = function (hostname, options, callback) { if (typeof options === 'function') { callback = options; options = {}; } options = options || {}; const family = options.family === 6 ? 6 : 4; const direct = localResolve(hostname, family); if (direct) { return process.nextTick(() => options.all ? callback(null, [direct]) : callback(null, direct.address, direct.family)); } // rama movil: primero el resolutor del sistema (getaddrinfo), que es el que // respeta la VPN y el DNS privado de Android. Upstream iba siempre a // 8.8.8.8/1.1.1.1, y las VPN que evitan fugas de DNS (Mullvad, por ejemplo) // o las redes que bloquean DNS externos los rechazan: no se encontraba // ningun pub por nombre y unirse a uno "no hacia nada". Los publicos quedan // de respaldo, para los moviles donde getaddrinfo no contesta. // Los dos caminos compiten: el del sistema sale ya y, si en SYSTEM_LOOKUP_MS // no ha contestado o falla, se pregunta tambien a los publicos. Gana la primera // respuesta buena; si fallan los dos, se devuelve el error del sistema, que // dice mas ("no existe") que el de unos servidores quiza bloqueados. let done = false, sysErr = null, pubErr = null, sysDone = false, pubDone = false, pubStarted = false; const finish = (err, address, fam) => { if (done) return; done = true; clearTimeout(timer); if (err) return callback(err); if (options.all) return callback(null, Array.isArray(address) ? address : [{ address, family: fam }]); if (Array.isArray(address)) return callback(null, address[0].address, address[0].family); return callback(null, address, fam); }; const bothFailed = () => { if (sysDone && pubDone) finish(sysErr || pubErr || new Error('ENOTFOUND ' + hostname)); }; const viaPublic = () => { if (pubStarted) return; pubStarted = true; const resolver = family === 6 ? dns.resolve6 : dns.resolve4; resolver.call(dns, hostname, (err, addrs) => { pubDone = true; if (err || !addrs || !addrs.length) { pubErr = err || new Error('ENOTFOUND ' + hostname); return bothFailed(); } finish(null, options.all ? addrs.map((x) => ({ address: x, family })) : addrs[0], family); }); }; const timer = setTimeout(viaPublic, SYSTEM_LOOKUP_MS); systemLookup.call(dns, hostname, { family, all: !!options.all }, (err, address, fam) => { sysDone = true; if (!err) return finish(null, address, fam); sysErr = err; if (pubStarted) bothFailed(); else viaPublic(); }); }; dns.lookup = safeLookup; if (dns.promises) { dns.promises.lookup = (hostname, options) => new Promise((resolve, reject) => { safeLookup(hostname, options || {}, (err, address, family) => { if (err) return reject(err); if (options && options.all) return resolve(address); resolve({ address, family }); }); }); } } catch (e) {} const backendPath = path.join(__dirname, 'src', 'backend', 'backend.js'); console.log('[Oasis] Launching Oasis Social Network Utopia...'); console.log('[Oasis] Backend path:', backendPath); console.log('[Oasis] HOME:', process.env.HOME); try { require(backendPath); console.log('[Oasis] Backend started on port 3000'); } catch (error) { console.error('[Oasis] Error starting backend:', error); }