Plataformas
Ruby
Runlight funciona con Ruby 3.2 o posterior, dentro de una aplicación Rack como Sinatra, Hanami o Roda, o en un dominio propio como servidor independiente.
La gema de Ruby es Runlight escrito de nuevo en Ruby. Sirve el mismo panel y la misma API, y da a cada petición la misma respuesta que da la biblioteca de TypeScript. Sus cifras van en las mismas tablas, así que cualquiera de los dos puede leer una base de datos que haya escrito el otro. Necesita Ruby 3.2 o posterior, y guarda sus datos a través de ActiveRecord, que trae consigo. Para una aplicación Rails, la guía de Rails tiene un engine y un generador que hacen la configuración por ti.
Instalación
Añade la gema con el driver de tu base de datos.
bash
bundle add runlight sqlite3Usa pg para Postgres, o trilogy o mysql2 para MySQL y MariaDB, en lugar de sqlite3.
Crea la instancia
Crea una instancia cuando arranque la aplicación y compártela.
runlight.rb
require "runlight"
RL = Runlight.new(
store: Runlight::Stores.sqlite("data/runlight.db"),
site: { name: "example.com", hostnames: ["example.com"], timezone: "Europe/London" },
)Las opciones tienen los nombres de Configuración, escritos en snake case, así que sites, trust_proxy, rate_limit, mail y managed_sites funcionan como allí. Las tablas se crean en la primera petición.
Almacenes
Las tablas de Runlight empiezan por rl_. Cada almacén acepta prefix: para usar otro en su lugar, como Runlight::Stores.sqlite(path, prefix: "wp_rl_"), así que dos aplicaciones que comparten una base de datos mantienen cada una sus propias tablas. Un prefijo tiene como máximo 32 letras, dígitos y guiones bajos, y no empieza por un dígito. store.tables lista las tablas del almacén por nombre, para una aplicación que quiera quitar Runlight.
SQLite
ruby
Runlight::Stores.sqlite("data/runlight.db")Guarda el archivo fuera de cualquier carpeta que sirva el servidor web. La carpeta se crea si no existe, y la base de datos funciona en modo WAL, así que varios procesos pueden compartirla.
MySQL y MariaDB
ruby
Runlight::Stores.mysql("mysql://runlight:password@127.0.0.1:3306/runlight")Este almacén funciona con MySQL 8.0.20 o posterior y MariaDB 11.4 o posterior, a través de la gema trilogy si está instalada y de mysql2 si no. También vale una URL mariadb://. statement_timeout: 30_000 detiene cualquier consulta pasados esos milisegundos, y el valor por defecto es 120000, como en Configuración.
Postgres
ruby
Runlight::Stores.postgres("postgres://runlight:password@127.0.0.1:5432/runlight")Este almacén necesita la gema pg. También acepta statement_timeout:, y schema: "analytics" guarda las tablas en un schema propio. Runlight::Stores.url elige el almacén a partir de un DATABASE_URL que empiece por postgres://, mysql://, mariadb:// o sqlite:.
La base de datos ActiveRecord de la propia aplicación
ruby
Runlight::Stores.active_recordEste almacén guarda las tablas de Runlight en la base de datos a la que ya se conecta el ActiveRecord de la aplicación, junto a las tablas propias de la aplicación. Pasa una clase de modelo abstracta, como Runlight::Stores.active_record(AnalyticsRecord), para usar otra de las bases de datos de la aplicación. Sus escrituras se unen a cualquier transacción que la aplicación tenga abierta.
Aplicaciones Rack
Pon Runlight delante de la aplicación en config.ru.
config.ru
require_relative "runlight"
require_relative "app"
use Runlight::RackApp, runlight: RL, base_path: "/runlight"
run AppRunlight responde a las rutas bajo /runlight, a los enlaces cortos en /go y a cualquier dominio de enlaces que añadas en Ajustes, y pasa cualquier otra petición a la aplicación. También registra de paso los accesos de los agentes de IA, lo que no le cuesta tiempo a nadie más. Runlight comprueba sus propias peticiones, así que va antes que cualquier middleware CSRF. Añade el script a cada página, justo antes de </head>.
html
<script defer src="/runlight/s.js"></script>Después define RUNLIGHT_TOKEN como una cadena larga y aleatoria y abre una vez /runlight/?token= seguido de esa cadena para iniciar sesión, como describe Primeros pasos. Con accounts: true en las opciones y un RUNLIGHT_SECRET, cada persona inicia sesión con su propio correo y contraseña, como en Cuentas. Pasa token: para definir el token en el código, donde una cadena vacía mantiene cerrado el panel y nil lo deja abierto a todo el mundo.
RL.rack_app(base_path: "/runlight") es la misma aplicación sin nada detrás, para un config.ru que la monte en una ruta propia con map.
Un enlace corto en /go/<name> sin ningún enlace con ese nombre sigue hacia la aplicación, así que responde su propia página 404, como la de Rails. RL.rack_app no tiene ninguna aplicación detrás y responde él mismo con un 404. En un dominio de enlaces, /go/<name> es un 404 como cualquier otra ruta que no sea uno de los enlaces de ese dominio.
La comprobación programada
La comprobación programada envía los informes por email y mantiene los datos en orden. Llámala cada pocos minutos desde cron, un programador de tareas o un hilo propio.
ruby
RL.checkCuando nada en la aplicación puede ejecutarla con un temporizador, define CRON_SECRET y haz que un programador de tareas externo llame a /runlight/api/check con él, como muestra Comprobación programada.
El servidor independiente
El comando runlight de la gema ejecuta Runlight en un dominio propio, como stats.example.com, igual que el servidor independiente. Sirve el panel en la raíz, gestiona los sitios desde el panel, y tiene cuentas con inicio de sesión y enlaces cortos en cualquier dominio que apuntes hacia él.
bash
mkdir stats && cd stats
bundle init && bundle add runlight sqlite3 puma
bundle exec runlight serveEl servidor escucha en el puerto 3000, o en PORT. Se ejecuta con Puma cuando la gema está instalada y con WEBrick si no, y el config.ru de la carpeta lo ejecuta con cualquier otro servidor Rack. Los datos viven en runlight-data, dentro de la carpeta desde la que lo arrancas. En su primer arranque muestra un enlace con un código de un solo uso que crea la primera cuenta, y bundle exec runlight setup vuelve a mostrar el enlace. Los roles, las invitaciones, el inicio de sesión en dos pasos y la forma de añadir sitios funcionan como en el servidor independiente.
Los ajustes vienen de las variables de entorno que lee el drop-in de PHP, como RUNLIGHT_URL, DATABASE_URL, DATA_DIR, RUNLIGHT_SECRET, TRUST_PROXY y RUNLIGHT_GEO, o de un config.rb en la carpeta que devuelva un Hash con los mismos nombres. Si ambos están definidos, ganan las variables de entorno. El servidor ejecuta la comprobación programada cada cinco minutos, y bundle exec runlight cron la ejecuta desde cron para un servidor que no está siempre en marcha.
El resto de lo que hace el comando aparece en bundle exec runlight --help. password da a una cuenta una contraseña nueva y la muestra, migrate actualiza las tablas al momento y agents lee los agentes de IA del log de acceso de un servidor web, como hace el del drop-in de PHP.
En qué se diferencia de la biblioteca de TypeScript
La gema de Ruby pasa las pruebas de conformidad que se exigen a la biblioteca de TypeScript, en SQLite, Postgres, MySQL y MariaDB. Las diferencias vienen de cómo se ejecutan las aplicaciones Ruby.
- El pool de conexiones es el de ActiveRecord. Cada almacén que abre su propia base de datos tiene un pool de cinco conexiones por proceso, y el pool de ActiveRecord de la propia aplicación sirve a
Runlight::Stores.active_record. - Lo que la biblioteca de TypeScript hace en segundo plano, como borrar visitas después de elegir una retención más corta, se ejecuta una vez enviada la respuesta, cuando el servidor Rack cierra el cuerpo de la respuesta.
- Los límites de contraseñas incorrectas se guardan en la base de datos, así que todos los procesos los comparten. El límite de peticiones del tracker vive en pequeños archivos en la carpeta temporal del sistema, que comparten todos los procesos de una misma máquina.
- Los informes por email dan formato a números, fechas, importes y nombres de países a partir de una copia de los datos de ICU que usa Node, ya que Ruby no trae ninguno.