Desarrollo de Extensiones para fast-cli: Guía Avanzada en Personalización y Mejoras Funcionales

Introducción a la Extensibilidad de fast-cli

fast-cli es una herramienta de línea de comadnos para evaluar la velocidad de red utilizando fast.com. Este tutorial aborda la creación de extensiones que permiten adaptar salidas y funcionalidades según necesidades específicas.

Razones para Ampliar fast-cli

La extensibilidad ofrece beneficios clave, tales como:

  • Formatos de datos personalizados: Generar resultados en CSV, XML, HTML u otros formatos estructurados.
  • Integración con sistemas de monitoreo: Enviar métricas a plataformas como Prometheus o Grafana.
  • Tareas programadas: Implementar pruebas periódicas para registrar el historial de calidad de red.
  • Alertas configurables: Notificar automáticamente cuando la velocidad caiga por debajo de umbrales definidos.

Análisis de la Estructura del Proyecto

Para desarrollar extensiones, es fundamental comprender la arquitectura de fast-cli:

fast-cli/
├── source/
│   ├── cli.tsx          # Entrada CLI y análisis de argumentos
│   ├── ui.tsx           # Componentes de interfaz de usuario
│   ├── api.tsx          # Interacción con la API de fast.com
│   ├── types.ts         # Definiciones de tipos
│   └── utilities.ts     # Funciones auxiliares
├── package.json         # Configuración y dependencias
└── tsconfig.json        # Configuración de TypeScript

Tipos de Datos Esenciales

En source/types.ts se define la estructura completa de los datos de medición:

export type RedDatos = {
  readonly velocidadDescarga: number;
  readonly velocidadSubida: number;
  readonly unidadDescarga: UnidadVelocidad;
  readonly datosDescargados: number;
  readonly unidadSubida: UnidadVelocidad;
  readonly datosSubidos: number;
  readonly latencia: number;
  readonly bloatBuffer: number;
  readonly ubicacionUsuario: string;
  readonly ubicacionesServidor: string[];
  readonly ipUsuario: string;
  readonly completado: boolean;
};

Implementación de Formatos de Salida Personalizados

1. Añadir Parámetros CLI Nuevos

En source/cli.tsx, se extienden los flags del comando para soportar formatos alternativos:

flags: {
  // Parámetros existentes omitidos por brevedad
  csv: {
    type: 'boolean',
    description: 'Emitir resultados en formato CSV'
  },
  xml: {
    type: 'boolean', 
    description: 'Emitir resultados en formato XML'
  },
  html: {
    type: 'boolean',
    description: 'Emitir resultados en formato HTML'
  }
} as const,

2. Crear Módulos de Formateo

Desarrollar source/formatos.ts con funciones para cada formato:

export function aCSV(datos: RedDatos): string {
  const fechaHora = new Date().toISOString();
  return `${fechaHora};${datos.velocidadDescarga};${datos.unidadDescarga};${datos.velocidadSubida};${datos.unidadSubida};${datos.latencia};${datos.ubicacionUsuario}`;
}

export function aXML(datos: RedDatos): string {
  return `<?xml version="1.0" encoding="UTF-8"?>
<prueba_red>
  <marca_tiempo>${new Date().toISOString()}</marca_tiempo>
  <descarga>
    <velocidad>${datos.velocidadDescarga}</velocidad>
    <unidad>${datos.unidadDescarga}</unidad>
  </descarga>
  <subida>
    <velocidad>${datos.velocidadSubida}</velocidad>
    <unidad>${datos.unidadSubida}</unidad>
  </subida>
  <latencia>${datos.latencia}</latencia>
  <ubicacion>${datos.ubicacionUsuario}</ubicacion>
</prueba_red>`;
}

3. Integración en la Interfaz

Modificar source/ui.tsx para aplicar el formateo según la selección:

import { aCSV, aXML, aHTML } from './formatos.js';

const formatearSalida = (datos: RedDatos, formato: string) => {
  switch(formato) {
    case 'csv':
      return aCSV(datos);
    case 'xml':
      return aXML(datos);
    case 'html':
      return aHTML(datos);
    case 'json':
      return JSON.stringify(datos, null, 2);
    default:
      return `${datos.velocidadDescarga} ${datos.unidadDescarga}`;
  }
};

Casos Prácticos de Mejora

Caso 1: Script de Monitoreo Periódico

Crear monitor.js para ejecutar pruebas regulares y almacenar datos:

#!/usr/bin/env node
import { ejecutar } from 'child_process';
import { agregarArchivo } from 'fs/promises';
import { programar } from 'node-cron';

programar('*/30 * * * *', async () => {
  ejecutar('fast --upload --json', async (error, salida) => {
    if (error) {
      console.error('Fallo en medición:', error);
      return;
    }
    
    const datos = JSON.parse(salida);
    const registro = {
      marca_tiempo: new Date().toISOString(),
      ...datos
    };
    
    const lineaCSV = `${registro.marca_tiempo},${registro.velocidadDescarga},${registro.velocidadSubida},${registro.latencia}\n`;
    await agregarArchivo('historial-velocidad.csv', lineaCSV);
    
    if (registro.velocidadDescarga < 50) { // Umbral de 50 Mbps
      console.warn('⚠️ ¡Velocidad de red por debajo del umbral!');
      // Lógica para enviar notificaciones
    }
  });
});

Caso 2: Integración con Prometheus

Desarrollar un exportador para exponer métricas:

import express from 'express';
import { ejecutar } from 'child_process';

const aplicacion = express();
const puerto = 9100;

aplicacion.get('/metricas', async (solicitud, respuesta) => {
  try {
    const datosRed = await obtenerDatosVelocidad();
    
    const metricas = `
# HELP velocidad_descarga_red Velocidad de descarga en Mbps
# TYPE velocidad_descarga_red gauge
velocidad_descarga_red ${datosRed.velocidadDescarga}

# HELP velocidad_subida_red Velocidad de subida en Mbps  
# TYPE velocidad_subida_red gauge
velocidad_subida_red ${datosRed.velocidadSubida}

# HELP latencia_red_ms Latencia de red en milisegundos
# TYPE latencia_red_ms gauge
latencia_red_ms ${datosRed.latencia}
    `;
    
    respuesta.set('Content-Type', 'text/plain');
    respuesta.send(metricas);
  } catch (error) {
    respuesta.status(500).send(error.message);
  }
});

async function obtenerDatosVelocidad() {
  return new Promise((resolver, rechazar) => {
    ejecutar('fast --upload --json', (error, salida) => {
      if (error) rechazar(error);
      resolver(JSON.parse(salida));
    });
  });
}

aplicacion.listen(puerto, () => {
  console.log(`Exportador Prometheus escuchando en puerto ${puerto}`);
});

Técnicas Avanzadas de Extensión

1. Arquitectura de Sistema de Plugins

Diseñar interfaces para plugins dinámicos:

interface PluginFastCli {
  nombre: string;
  version: string;
  registrar: (cli: any) => void;
}

class GestorPlugins {
  private plugins: PluginFastCli[] = [];
  
  registrar(plugin: PluginFastCli) {
    this.plugins.push(plugin);
  }
  
  aplicarTodos(cli: any) {
    this.plugins.forEach(plugin => plugin.registrar(cli));
  }
}

2. Servidores de Prueba Personalizados

Adaptar source/api.tsx para permitir servidores alternativos:

export async function medirVelocidad(opciones: {
  subida?: boolean;
  verboso?: boolean;
  urlServidor?: string; // URL de servidor personalizado
} = {}) {
  const servidor = opciones.urlServidor || 'https://fast.com';
  // Implementación de medición con servidor configurado
}

3. Sistema de Puntuación de Calidad de Red

Calcular un puntaje basado en métricas:

export function calcularPuntajeRed(datos: RedDatos): number {
  const puntajeDescarga = Math.min(datos.velocidadDescarga / 100, 1) * 40;
  const puntajeSubida = Math.min(datos.velocidadSubida / 50, 1) * 30;
  const puntajeLatencia = Math.max(0, 1 - datos.latencia / 100) * 20;
  const puntajeEstabilidad = datos.bloatBuffer < 50 ? 10 : 0;
  
  return puntajeDescarga + puntajeSubida + puntajeLatencia + puntajeEstabilidad;
}

Pruebas y Mejores Prácticas de Despliegue

Pruebas Unitarias para Extensiones

Crear pruebas para validar funcionalidades extendidas:

import test from 'ava';
import { aCSV, aXML } from './source/formatos.js';

test('El formateador CSV funciona correctamente', t => {
  const datosSimulados = {
    velocidadDescarga: 100,
    unidadDescarga: 'Mbps',
    velocidadSubida: 50,
    unidadSubida: 'Mbps',
    latencia: 10,
    ubicacionUsuario: 'Madrid, ES'
  };
  
  const resultado = aCSV(datosSimulados);
  t.true(resultado.includes('100'));
  t.true(resultado.includes('Mbps'));
  t.true(resultado.includes('Madrid'));
});

Construcción y Distribución

Configurar scripts en package.json para manejar extensiones:

{
  "scripts": {
    "build": "tsc",
    "build:extendido": "tsc && node scripts/construir-extensiones.js",
    "test:extensiones": "ava test/extensiones.test.js"
  }
}

Preguntas Frecuentes

¿Qué conocimientso se requieren para extender fast-cli? Es necesario dominar Node.js, TypeScript, desarrollo de herramientas CLI y principios de medición de red.

¿Cómo mantener compatibilidad con versiones anteriores? Evitar modificaciones en la lógica central, usar mecanismos de plugins o configuraciones para añadir funciones.

¿Cuál es el método para distribuir extensiones? Publicar como paquete npm independiente o compartir mediante repositorios, instalando con npm install.

¿Recomendaciones para optimizar rendimiento? Implementar caché para evitar repeticiones, procesamiento por lotes y operaciones asíncronas para tareas costosas.

Etiquetas: fast-cli TypeScript Node.js CLI medición de velocidad

Publicado el 6-22 21:22