Todas as docs

Início

  1. 01Primeiros passos
  2. 02Instalação
  3. 03Rastreamento

Recursos

  1. 04O painel
  2. 05Metas
  3. 06Links curtos
  4. 07Origens e agentes de IA
  5. 08Relatórios por email
  6. 09Verificação agendada
  7. 10Pergunte à sua IA

Referência

  1. 11Configuração
  2. 12API HTTP

Plataformas

  1. 13Servidor independente
  2. 14PHP
  3. 15WordPress
  4. 16Drupal
  5. 17Craft CMS
  6. 18Python
  7. 19Rails
  8. 20Ruby
  9. 21Go
  10. 22Java
  11. 23.NET
  12. 24Elixir
  13. 25Rust

Confiança

  1. 26Privacidade

Plataformas

Ruby

O Runlight roda em Ruby 3.2 ou mais recente, dentro de um app Rack como Sinatra, Hanami ou Roda, ou num domínio próprio como servidor independente.

A gem Ruby é o Runlight reescrito em Ruby. Ela serve o mesmo painel e a mesma API, e dá a cada requisição a mesma resposta que a biblioteca TypeScript dá. Os números vão para as mesmas tabelas, então qualquer uma das duas consegue ler um banco de dados que a outra escreveu. Ela precisa do Ruby 3.2 ou mais recente e guarda os dados pelo ActiveRecord, que já vem junto com ela. Para um app Rails, o guia do Rails tem uma engine e um gerador que fazem a configuração para você.

Instalação

Adicione a gem junto com o driver do seu banco de dados.

bash

bundle add runlight sqlite3

No lugar de sqlite3, use pg para Postgres, ou trilogy ou mysql2 para MySQL e MariaDB.

Crie a instância

Crie uma instância quando o app inicia e compartilhe essa instância.

runlight.rb

require "runlight"

RL = Runlight.new(
  store: Runlight::Stores.sqlite("data/runlight.db"),
  site: { name: "example.com", hostnames: ["example.com"], timezone: "Europe/London" },
)

As opções têm os nomes de Configuração, escritos em snake case, então sites, trust_proxy, rate_limit, mail e managed_sites funcionam como lá. As tabelas são criadas na primeira requisição.

Stores

As tabelas do Runlight começam com rl_. Todo store aceita prefix: para usar outro prefixo no lugar, como Runlight::Stores.sqlite(path, prefix: "wp_rl_"), para que dois apps que compartilham um banco de dados mantenham cada um as suas tabelas. Um prefixo tem até 32 letras, dígitos e sublinhados e não começa com dígito. store.tables lista as tabelas do store pelo nome, para um app que esteja removendo o Runlight.

SQLite

ruby

Runlight::Stores.sqlite("data/runlight.db")

Mantenha o arquivo fora de qualquer pasta que o servidor web sirva. A pasta é criada quando não existe, e o banco de dados roda em modo WAL, então vários processos podem compartilhá-lo.

MySQL e MariaDB

ruby

Runlight::Stores.mysql("mysql://runlight:password@127.0.0.1:3306/runlight")

Este store funciona com MySQL 8.0.20 ou mais recente e MariaDB 11.4 ou mais recente, pela gem trilogy quando ela está instalada e pela mysql2 caso contrário. Uma URL mariadb:// também funciona. statement_timeout: 30_000 interrompe qualquer consulta depois desse número de milissegundos, e o padrão é 120000, como em Configuração.

Postgres

ruby

Runlight::Stores.postgres("postgres://runlight:password@127.0.0.1:5432/runlight")

Este store precisa da gem pg. Ele também aceita statement_timeout:, e schema: "analytics" mantém as tabelas num schema próprio. Runlight::Stores.url escolhe o store a partir de uma DATABASE_URL que começa com postgres://, mysql://, mariadb:// ou sqlite:.

O banco de dados ActiveRecord do próprio app

ruby

Runlight::Stores.active_record

Este store guarda as tabelas do Runlight no banco de dados ao qual o ActiveRecord do app já se conecta, ao lado das tabelas do próprio app. Passe uma classe de modelo abstrata, como Runlight::Stores.active_record(AnalyticsRecord), para usar outro banco de dados do app. As escritas dele entram numa transação que o app tenha aberta.

Apps Rack

Coloque o Runlight na frente do app no config.ru.

config.ru

require_relative "runlight"
require_relative "app"

use Runlight::RackApp, runlight: RL, base_path: "/runlight"
run App

O Runlight responde aos caminhos sob /runlight, aos links curtos em /go e a qualquer domínio de links que você adicionar em Configurações, e passa todas as outras requisições para o app. Ele também registra as leituras de agentes de IA de passagem, o que não custa tempo para mais ninguém. O Runlight verifica as próprias requisições, então ele vem antes de qualquer middleware de CSRF. Adicione o script em todas as páginas, logo antes de </head>.

html

<script defer src="/runlight/s.js"></script>

Depois defina RUNLIGHT_TOKEN como uma string longa e aleatória e abra /runlight/?token= seguido dessa string uma vez para entrar, como descreve Primeiros passos. Com accounts: true nas opções e um RUNLIGHT_SECRET, as pessoas entram com o próprio e-mail e senha, como em Contas. Passe token: para definir o token no código. Uma string vazia mantém o painel fechado, e nil o deixa aberto para todo mundo.

RL.rack_app(base_path: "/runlight") é o mesmo app sem nada por trás, para um config.ru que o monta num caminho próprio com map.

Um link curto em /go/<name> sem nenhum link com esse nome segue para o app, então a própria página 404 dele responde, como a do Rails. RL.rack_app não tem nenhum app por trás e responde ele mesmo com um 404. Num domínio de links, /go/<name> é um 404 como qualquer outro caminho que não seja um dos links desse domínio.

A verificação agendada

A verificação agendada envia os relatórios por email e mantém os dados em ordem. Chame-a a cada poucos minutos pelo cron, por um agendador de jobs ou por uma thread sua.

ruby

RL.check

Quando nada no app consegue rodá-la num timer, defina CRON_SECRET e faça um agendador externo chamar /runlight/api/check com ele, como mostra Verificação agendada.

O servidor independente

O comando runlight da gem roda o Runlight num domínio próprio, como stats.example.com, como faz o servidor independente. Ele serve o painel na raiz, mantém os sites no painel e tem contas com login e links curtos em qualquer domínio que você apontar para ele.

bash

mkdir stats && cd stats
bundle init && bundle add runlight sqlite3 puma
bundle exec runlight serve

O servidor escuta na porta 3000, ou em PORT. Ele roda sob o Puma quando a gem está presente e sob o WEBrick caso contrário, e o config.ru da pasta o roda sob qualquer outro servidor Rack. Os dados ficam em runlight-data, na pasta de onde você o inicia. Na primeira vez que inicia, ele mostra um link com um código de uso único que cria a primeira conta, e bundle exec runlight setup mostra o link de novo. Funções, convites, login em duas etapas e a adição de sites funcionam como no servidor independente.

As configurações vêm das variáveis de ambiente que o drop-in em PHP lê, como RUNLIGHT_URL, DATABASE_URL, DATA_DIR, RUNLIGHT_SECRET, TRUST_PROXY e RUNLIGHT_GEO, ou de um config.rb na pasta que retorna um Hash com os mesmos nomes. As variáveis de ambiente têm prioridade quando as duas estão definidas. O servidor roda a verificação agendada a cada cinco minutos, e bundle exec runlight cron a roda pelo cron para um servidor que não fica sempre no ar.

O resto do que o comando faz está em bundle exec runlight --help. password dá uma nova senha a uma conta e a mostra, migrate atualiza as tabelas na hora, e agents lê os agentes de IA do log de acesso de um servidor web, como faz o do drop-in em PHP.

Diferenças em relação à biblioteca TypeScript

A gem Ruby passa nos testes de conformidade aos quais a biblioteca TypeScript é submetida, em SQLite, Postgres, MySQL e MariaDB. As diferenças vêm da forma como os apps Ruby rodam.

  • O pool de conexões é o do ActiveRecord. Cada store que abre o próprio banco de dados tem um pool de cinco conexões por processo, e o pool ActiveRecord do próprio app atende Runlight::Stores.active_record.
  • O que a biblioteca TypeScript faz em segundo plano, como apagar visitas depois que um período de retenção menor é escolhido, roda depois que a resposta é enviada, quando o servidor Rack fecha o corpo da resposta.
  • Os limites de senha errada ficam no banco de dados, então todos os processos os compartilham. O limite de requisições do script de rastreamento fica em pequenos arquivos na pasta temporária do sistema, que todos os processos de uma mesma máquina compartilham.
  • Os relatórios por email formatam números, datas, valores em dinheiro e nomes de países a partir de uma cópia dos dados ICU que o Node usa, já que o Ruby não traz nenhum.