Skip to content

iphoends-servidor #66296

Description

const WebSocket = require('ws');
const http = require('http');
const url = require('url');

// === CONFIGURACIÓN ===
const PUERTO = 8080;
const PUERTO_HTTP = 3000;

// === SERVIDOR HTTP (sirve tu interfaz) ===
const servidorHTTP = http.createServer((req, res) => {
if (req.url === '/') {
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
// Aquí va tu interfaz completa — la cargamos desde el archivo o la insertamos abajo
res.end(`

<title>Iphoends — Windows 98</title> <style> :root { --win98-gray: #c0c0c0; --win98-dark: #808080; --win98-light: #ffffff; --win98-blue: #80; } * { margin:0; padding:0; box-sizing:border-box; font-family:"MS Sans Serif", Tahoma, sans-serif; font-size:11px; } body { background: #8080; height:100vh; overflow:hidden; user-select:none; } .desktop { height:calc(100vh - 28px); position:relative; padding:10px; } .icon { width:70px; text-align:center; color:white; cursor:pointer; padding:4px; border:1px solid transparent; } .icon:hover { background:rgba(0,0,128,0.3); border:1px dotted #fff; } .icon span { display:block; font-size:32px; margin-bottom:2px; } .icon .nombre { font-size:11px; text-shadow:1px 1px 0 #000; } .taskbar { position:fixed; bottom:0; left:0; right:0; height:28px; background:#c0c0c0; border-top:2px solid #fff; display:flex; align-items:center; padding:2px 4px; } .start-btn { background:#c0c0c0; border:2px outset #fff; padding:2px 8px; font-weight:bold; cursor:pointer; } .start-btn:active { border-style:inset; } .taskbar-windows { flex:1; display:flex; gap:2px; margin-left:6px; } .task-btn { background:#c0c0c0; border:2px outset #fff; padding:2px 10px; width:140px; overflow:hidden; text-overflow:ellipsis; cursor:pointer; } .task-btn.active { border-style:inset; background:#e0e0e0; } .system-tray { margin-left:auto; padding:2px 6px; border:1px inset #fff; } .window { position:absolute; background:#c0c0c0; border:2px outset #fff; box-shadow:3px 3px 8px rgba(0,0,0,0.4); min-width:320px; min-height:200px; display:none; } .window.show { display:block; } .window-title { background:linear-gradient(to right, #80, #1084d0); color:white; padding:2px 4px; display:flex; align-items:center; font-weight:bold; cursor:move; } .window-title.inactive { background:linear-gradient(to right, #808080, #b0b0b0); } .window-controls { margin-left:auto; display:flex; gap:2px; } .win-btn { width:16px; height:16px; background:#c0c0c0; border:2px outset #fff; font-weight:bold; cursor:pointer; display:flex; align-items:center; justify-content:center; } .win-btn:active { border-style:inset; } .window-content { padding:10px; overflow:auto; height:calc(100% - 54px); } label { display:block; margin:6px 0 2px; font-weight:bold; } input, textarea { width:100%; padding:3px; border:2px inset #fff; background:white; font-size:12px; } button { background:#c0c0c0; border:2px outset #fff; padding:4px 12px; cursor:pointer; margin:4px 2px; font-weight:bold; } button:active { border-style:inset; } button.primary { background:#0066cc; color:white; } button.danger { background:#cc0000; color:white; } .btn-row { text-align:right; margin-top:10px; } .status-conectado { color:green; font-weight:bold; } .status-esperando { color:orange; font-weight:bold; } .status-desconectado { color:gray; } .alert-box { position:fixed; top:50%; left:50%; transform:translate(-50%, -50%); width:340px; background:#c0c0c0; border:2px outset #fff; z-index:9999; display:none; box-shadow:4px 4px 10px rgba(0,0,0,0.5); } .alert-box.show { display:block; } .alert-content { padding:15px; } .alert-buttons { text-align:center; margin-top:15px; } hr { margin:8px 0; border-color:#808080; } .conectado { color:green; } .desconectado { color:red; } </style>
📞Llamada
✉️Mensaje
📦Paquete
🔗Conexión
🪟 Inicio
00:00
🔗 Conexión al Servidor
− ×
Estado:

Desconectado

<label>ID de Conexión:</label>
<input type="text" id="miID" readonly placeholder="Generando...">

<label>Conectar con (ID del otro dispositivo):</label>
<input type="text" id="idDestino" placeholder="Escribe el ID del otro celular">

<div class="btn-row">
  <button class="primary" onclick="conectarServidor()">🔌 Conectar</button>
  <button onclick="desconectarServidor()">❌ Desconectar</button>
</div>
<p style="margin-top:8px; font-size:10px; color:#666;">Servidor: ws://localhost:8080</p>
📞 Llamada
− ×
Número de Teléfono:
<label>Estado:</label>
<p id="estadoLlamada" class="status-desconectado">Listo</p>

<div class="btn-row">
  <button class="primary" onclick="hacerLlamada()">📞 Llamar</button>
  <button class="danger" onclick="colgar()">📞 Colgar</button>
</div>
✉️ Enviar Mensaje
− ×
Nombre del Cliente:
<label>Correo Electrónico:</label>
<input type="email" id="correoCliente" placeholder="correo@ejemplo.com">

<label>Teléfono (EE.UU./Canadá):</label>
<input type="tel" id="telExtranjero" placeholder="+1 XXX XXX XXXX">

<label>Mensaje:</label>
<textarea id="textoMensaje" rows="3">📦 Su paquete está en camino. Escanee el enlace para ver detalles y aceptar entrega.</textarea>

<div class="btn-row">
  <button class="primary" onclick="enviarPorWhatsApp()">💬 WhatsApp</button>
  <button onclick="enviarPorSMS()">📱 SMS</button>
</div>
📦 Vinculación Paquete
− ×

🔐 Escanee o abra el enlace
Iniciar sesión con Google

<label>Estado de Vinculación:</label>
<p id="estadoVinculacion" class="status-esperando">Esperando aceptación...</p>

<div class="btn-row">
  <button onclick="copiarEnlace()">📋 Copiar Enlace</button>
  <button class="primary" onclick="enviarVinculacion()">📤 Enviar</button>
</div>
📞 Llamada Entrante

Número: —

Al contestar se establece vinculación de dispositivos.

📞 Contestar 📞 Rechazar
📦 Notificación de Paquete

Usted recibirá próximamente su paquete

Escanee el código QR y acepte para ingresar al portal y ver detalles.

✅ Aceptar ❌ Rechazar
<script> // === VARIABLES GLOBALES === let conexionWS = null; let miID = null; let dispositivoConectado = null; let arrastrando = null, offsetX = 0, offsetY = 0; // === RELOJ === function actualizarReloj() { const ahora = new Date(); document.getElementById('reloj').textContent = ahora.getHours().toString().padStart(2,'0') + ':' + ahora.getMinutes().toString().padStart(2,'0'); } setInterval(actualizarReloj, 1000); actualizarReloj(); // === GESTIÓN DE VENTANAS === const ventanasAbiertas = {}; function abrirVentana(nombre) { document.getElementById(`win-${nombre}`).classList.add('show'); ventanasAbiertas[nombre] = true; actualizarBarra(); } function cerrarVentana(nombre) { document.getElementById(`win-${nombre}`).classList.remove('show'); delete ventanasAbiertas[nombre]; actualizarBarra(); } function minimizar(nombre) { document.getElementById(`win-${nombre}`).classList.remove('show'); } function actualizarBarra() { const barra = document.getElementById('barraVentanas'); barra.innerHTML = ''; const nombres = { conexion: '🔗 Conexión', llamada: '📞 Llamada', mensaje: '✉️ Mensaje', vinculacion: '📦 Paquete' }; Object.keys(ventanasAbiertas).forEach(n => { const btn = document.createElement('button'); btn.className = 'task-btn'; btn.textContent = nombres[n]; btn.onclick = () => abrirVentana(n); barra.appendChild(btn); }); } // === ARRASTRE DE VENTANAS === function iniciarArrastre(e, id) { if (e.target.closest('.win-btn')) return; arrastrando = id; const win = document.getElementById(id); const rect = win.getBoundingClientRect(); offsetX = e.clientX - rect.left; offsetY = e.clientY - rect.top; } document.addEventListener('mousemove', e => { if (!arrastrando) return; const win = document.getElementById(arrastrando); win.style.left = (e.clientX - offsetX) + 'px'; win.style.top = (e.clientY - offsetY) + 'px'; }); document.addEventListener('mouseup', () => arrastrando = null); // === CONEXIÓN WEBSOCKET === function conectarServidor() { const direccion = 'ws://localhost:8080'; conexionWS = new WebSocket(direccion); conexionWS.onopen = () => { document.getElementById('estadoServidor').textContent = '✅ Conectado al servidor'; document.getElementById('estadoServidor').className = 'status-conectado'; }; conexionWS.onmessage = (evento) => { const datos = JSON.parse(evento.data); procesarMensaje(datos); }; conexionWS.onclose = () => { document.getElementById('estadoServidor').textContent = 'Desconectado'; document.getElementById('estadoServidor').className = 'status-desconectado'; dispositivoConectado = null; }; conexionWS.onerror = (err) => { document.getElementById('estadoServidor').textContent = 'Error de conexión'; alert('No se pudo conectar al servidor. ¿Está ejecutándose?'); }; } function desconectarServidor() { if (conexionWS) conexionWS.close(); } function procesarMensaje(datos) { switch(datos.tipo) { case 'tu-id': miID = datos.id; document.getElementById('miID').value = miID; break; case 'solicitud-conexion': document.getElementById('alertaVinculacion').classList.add('show'); break; case 'llamada-entrante': document.getElementById('numLlamador').textContent = datos.numero; document.getElementById('alertaLlamada').classList.add('show'); break; case 'conectado': dispositivoConectado = datos.desde; document.getElementById('estadoLlamada').textContent = '✅ Conectado — Vinculación activa'; document.getElementById('estadoLlamada').className = 'status-conectado'; document.getElementById('estadoVinculacion').textContent = '✅ Vinculación establecida'; document.getElementById('estadoVinculacion').className = 'status-conectado'; break; } } function enviarMensaje(datos) { if (conexionWS && conexionWS.readyState === WebSocket.OPEN) { conexionWS.send(JSON.stringify(datos)); } } // === FUNCIONES DE LLAMADAS === function hacerLlamada() { const numero = document.getElementById('numLlamada').value.trim(); const destino = document.getElementById('idDestino').value.trim(); if (!numero || !destino) { alert('Escribe número y ID del destino'); return; } document.getElementById('estadoLlamada').textContent = 'Llamando...'; document.getElementById('estadoLlamada').className = 'status-esperando'; enviarMensaje({ tipo: 'iniciar-llamada', destino: destino, numero: numero }); } function contestar() { document.getElementById('alertaLlamada').classList.remove('show'); enviarMensaje({ tipo: 'contestar' }); } function rechazarLlamada() { document.getElementById('alertaLlamada').classList.remove('show'); enviarMensaje({ tipo: 'rechazar' }); document.getElementById('estadoLlamada').textContent = 'Rechazada'; } function colgar() { enviarMensaje({ tipo: 'colgar' }); document.getElementById('estadoLlamada').textContent = 'Desconectado'; document.getElementById('estadoLlamada').className = 'status-desconectado'; document.getElementById('estadoVinculacion').textContent = 'Esperando aceptación...'; document.getElementById('estadoVinculacion').className = 'status-esperando'; } // === FUNCIONES DE MENSAJES === function enviarPorWhatsApp() { const nombre = document.getElementById('nombreCliente').value; const correo = document.getElementById('correoCliente').value; const telefono = document.getElementById('telExtranjero').value; const mensaje = document.getElementById('textoMensaje').value; if (!telefono) { alert('Escribe el teléfono del cliente'); return; } const enlaceVinculacion = `https://iphoends-vinculacion.com/?correo=${encodeURIComponent(correo)}&origen=${miID}`; const textoCompleto = encodeURIComponent( `📦 Estimado(a) ${nombre || 'Cliente'}:\n${mensaje}\n\n🔗 ${enlaceVinculacion}` ); window.open(`https://wa.me/${telefono.replace(/\D/g,'')}?text=${textoCompleto}`, '_blank'); alert('✅ Mensaje preparado con enlace de vinculación'); } function enviarPorSMS() { alert('📱 SMS listo — incluye enlace de vinculación'); } // === FUNCIONES DE VINCULACIÓN === function simularAceptar() { document.getElementById('alertaVinculacion').classList.add('show'); } function aceptarVinculacion() { document.getElementById('alertaVinculacion').classList.remove('show'); enviarMensaje({ tipo: 'aceptar-vinculacion' }); } function rechazarVinculacion() { document.getElementById('alertaVinculacion').classList.remove('show'); enviarMensaje({ tipo: 'rechazar-vinculacion' }); } function copiarEnlace() { const correo = document.getElementById('correoCliente').value || 'cliente@ejemplo.com'; const enlace = `https://iphoends-vinculacion.com/?correo=${encodeURIComponent(correo)}&origen=${miID || 'local'}`; navigator.clipboard.writeText(enlace).then(() => { alert('✅ Enlace copiado: ' + enlace); }); } function enviarVinculacion() { const destino = document.getElementById('idDestino').value.trim(); if (!destino) { alert('Escribe el ID del dispositivo destino'); return; } enviarMensaje({ tipo: 'solicitud-vinculacion', destino: destino, correo: document.getElementById('correoCliente').value }); alert('✅ Solicitud enviada'); } // Abrir conexión automáticamente abrirVentana('conexion'); abrirVentana('llamada'); abrirVentana('mensaje'); abrirVentana('vinculacion'); </script> `); });

// === SERVIDOR WEBSOCKET ===
const servidorWS = new WebSocket.Server({ port: PUERTO });
const dispositivosConectados = new Map();

console.log('🟢 Servidor Iphoends iniciando...');
console.log(📡 WebSocket: ws://localhost:${PUERTO});
console.log(🌐 Interfaz: http://localhost:${PUERTO_HTTP});

servidorWS.on('connection', (conexion) => {
const idDispositivo = generarID();
dispositivosConectados.set(idDispositivo, {
conexion,
estado: 'conectado',
emparejadoCon: null
});

console.log(✅ Dispositivo conectado: ${idDispositivo});

// Enviar su ID al cliente
conexion.send(JSON.stringify({
tipo: 'tu-id',
id: idDispositivo
}));

conexion.on('message', (mensaje) => {
try {
const datos = JSON.parse(mensaje.toString());
manejarMensaje(idDispositivo, datos);
} catch (e) {
console.log('⚠️ Mensaje inválido:', mensaje);
}
});

conexion.on('close', () => {
console.log(❌ Desconectado: ${idDispositivo});
dispositivosConectados.delete(idDispositivo);
});

conexion.on('error', (err) => {
console.log(⚠️ Error en ${idDispositivo}:, err.message);
});
});

function generarID() {
return 'IPH-' + Math.random().toString(36).substring(2, 10).toUpperCase();
}

function manejarMensaje(origen, datos) {
const dispOrigen = dispositivosConectados.get(origen);
if (!dispOrigen) return;

const destino = datos.destino;

switch (datos.tipo) {
case 'iniciar-llamada':
if (dispositivosConectados.has(destino)) {
dispositivosConectados.get(destino).conexion.send(JSON.stringify({
tipo: 'llamada-entrante',
desde: origen,
numero: datos.numero
}));
console.log(📞 Llamada de ${origen} → ${destino});
} else {
dispOrigen.conexion.send(JSON.stringify({
tipo: 'error',
mensaje: 'Dispositivo no encontrado'
}));
}
break;

case 'solicitud-vinculacion':
  if (dispositivosConectados.has(destino)) {
    dispositivosConectados.get(destino).conexion.send(JSON.stringify({
      tipo: 'solicitud-conexion',
      desde: origen,
      correo: datos.correo
    }));
    console.log(`🔗 Vinculación de ${origen} → ${destino}`);
  }
  break;
  
case 'contestar':
  if (destino && dispositivosConectados.has(destino)) {
    dispOrigen.emparejadoCon = destino;
    dispositivosConectados.get(destino).emparejadoCon = origen;
    dispositivosConectados.get(destino).conexion.send(JSON.stringify({
      tipo: 'conectado',
      desde: origen
    }));
    dispOrigen.conexion.send(JSON.stringify({
      tipo: 'conectado',
      desde: destino
    }));
    console.log(`✅ Conexión establecida: ${origen} ↔ ${destino}`);
  }
  break;
  
case 'aceptar-vinculacion':
  if (destino && dispositivosConectados.has(destino)) {
    dispOrigen.emparejadoCon = destino;
    dispositivosConectados.get(destino).emparejadoCon = origen;
    dispositivosConectados.get(destino).conexion.send(JSON.stringify({
      tipo: 'vinculacion-aceptada',
      desde: origen
    }));
    dispOrigen.conexion.send(JSON.stringify({
      tipo: 'conectado',
      desde: destino
    }));
  }
  break;
  
case 'rechazar':
case 'rechazar-vinculacion':
  if (destino && dispositivosConectados.has(destino)) {
    dispositivosConectados.get(destino).conexion.send(JSON.stringify({
      tipo: 'solicitud-rechazada',
      desde: origen
    }));
  }
  dispOrigen.emparejadoCon = null;
  if (dispositivosConectados.has(destino)) {
    dispositivosConectados.get(destino).emparejadoCon = null;
  }
  break;
  
case 'colgar':
  const par = dispOrigen.emparejadoCon;
  if (par && dispositivosConectados.has(par)) {
    dispositivosConectados.get(par).conexion.send(JSON.stringify({ tipo: 'colgado' }));
    dispositivosConectados.get(par).emparejadoCon = null;
  }
  dispOrigen.emparejadoCon = null;
  console.log(`📞 Llamada finalizada: ${origen}`);
  break;
  
case 'datos-remitente':
  if (destino && dispositivosConectados.has(destino)) {
    dispositivosConectados.get(destino).conexion.send(JSON.stringify({
      tipo: 'datos-cliente',
      nombre: datos.nombre,
      correo: datos.correo,
      telefono: datos.telefono
    }));
  }
  break;

}
}

servidorHTTP.listen(PUERTO_HTTP, () => {
console.log(🌐 Interfaz disponible en: http://localhost:${PUERTO_HTTP});
});

{
"name": "iphoends-servidor",
"version": "1.0.0",
"description": "Servidor de conexión Iphoends — Windows 98",
"main": "servidor-iphoends.js",
"scripts": {
"iniciar": "node servidor-iphoends.js"
},
"dependencies": {
"ws": "^8.14.0"
}
}

cd iphoends-servidor
npm install

npm run iniciar

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    invalidIssues and PRs that are invalid.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions