OllaHubBackend
API HTTP + WebSocket em Rust (Actix Web) para gerenciar o Ollama: verifica e instala o Ollama, lista e baixa modelos, faz chat com streaming e oferece criptografia AES-256-GCM, com JWT e Swagger UI.
Endpoints · Como funciona · Configuração · Executar · Limitações
Note
Estado do projeto: versão
0.1.0(Cargo.toml), com 3 commits entre 2025-11-05 e 2025-11-18 — estrutura inicial com API v2 modular, WebSocket, serviços de instalação do Ollama e documentação. A referência completa dos endpoints está emdocs/API.mde exemplos de cliente emdocs/API_EXAMPLES.md.
Important
Nem toda rota exige JWT. O middleware só protege
/api/v1/*,/v2/api/crypto*e/v2/api/models*. Ficam públicas — inclusivePOST /v2/api/ollama/install, que baixa e executa o instalador do Ollama —/health,/v2/health,/v2/api/ollama/*,/docse os WebSockets/v2/ws*. Por padrão o servidor escuta só em127.0.0.1; definaJWT_SECRETcom um valor próprio (o padrão échangeme-dev-secret) e só mudeHOSTsabendo disso.
Endpoints
Base URL padrão: http://127.0.0.1:8080. Swagger UI em /docs (OpenAPI em /api-doc/openapi.json).
| Método | Rota | JWT | O que faz |
|---|---|---|---|
| GET | /health |
não | Resposta simples "ok" |
| GET | /v2/health |
não | {"status":"ok"} |
| GET | /v2/api/ollama/check |
não | Estado do Ollama: no PATH, versão, API alcançável (reachable / unreachable / degraded), problemas encontrados |
| POST | /v2/api/ollama/install |
não | 202 com operation_id; instala em background e espera a API responder (até 60 s) |
| GET | /v2/api/models |
sim | Lista de modelos lida do modelList.json |
| POST | /v2/api/models/install |
sim | 202; baixa o modelo ({"name": "..."}) em background via /api/pull do Ollama |
| POST | /v2/api/crypto/set-key |
sim | Define a chave AES-256 ({"hex_key": "<64 hex>"}) e a grava em disco |
| POST | /v2/api/crypto/rotate-key |
sim | Gera uma chave nova e a devolve em hex |
| POST | /v2/api/crypto/encrypt |
sim | {"data": "texto"} → {"ciphertext": "<base64>"} |
| POST | /v2/api/crypto/decrypt |
sim | {"data": "<base64>"} → {"plaintext": "texto"} |
| GET/POST | /api/v1/users |
sim | Lista / cria usuário (nome ≥ 2 caracteres, e-mail válido) |
| GET/PUT/DELETE | /api/v1/users/{id} |
sim | Lê / atualiza / remove usuário |
| WS | /v2/ws |
não | Eco de mensagens e pong; veja Limitações |
| WS | /v2/ws/chat |
não | Chat com um modelo do Ollama (abaixo) |
Autenticação: Authorization: Bearer <jwt>, assinado em HS256 com JWT_SECRET, com as claims sub e exp
(e role opcional). A API não emite tokens — o segredo precisa ser o mesmo do serviço que os emite (o
.env.example indica o frontend).
Chat por WebSocket (/v2/ws/chat)
Envie um JSON por mensagem de texto:
{ "model": "llama3.2", "messages": [{ "role": "user", "content": "Olá" }], "options": { "temperature": 0.7 } }
O servidor responde com mensagens de status — {"status":"checking"}, ready, installing (com progress),
installed — e então as linhas JSON do /api/chat do Ollama. Se o modelo não estiver instalado, ele é baixado
antes de responder. Falhas chegam como {"error": "...", "done": true}. Há ping a cada 5 s e a conexão é
encerrada após 30 s sem atividade do cliente.
Como funciona
flowchart LR
C["Cliente<br/>OllaHub · curl"] -- "HTTP + JWT" --> S["Actix Web<br/>CORS · logging · JWT"]
C -- WebSocket --> S
S --> V1["/api/v1/users<br/>repositório em memória"]
S --> V2["/v2/api/*<br/>models · ollama · crypto"]
S --> WS["/v2/ws · /v2/ws/chat"]
V2 --> OL["Ollama :11434<br/>/api/tags · /api/pull · /api/chat"]
WS --> OL
V2 --> K["crypto_v2.key<br/>AES-256-GCM"]
S --> D["/docs<br/>Swagger UI"]
Módulos e detalhes técnicos
| Módulo | Papel |
|---|---|
src/main.rs, src/config.rs, src/state.rs |
Boot do servidor, configuração por variáveis de ambiente e AppContext (broker de eventos, criptografia, URL do Ollama, caminho do modelList.json, segredo JWT) |
src/routes/, src/controllers/, src/services/user_service.rs, src/repositories/, src/models/ |
CRUD de usuários (/api/v1) com documentação OpenAPI (utoipa) |
src/api/ |
Rotas v2: saúde, modelos, Ollama e criptografia |
src/core/models.rs |
Lê o modelList.json (objeto com models ou array), verifica modelos instalados (/api/tags) e baixa modelos (/api/pull) |
src/services/ollama_install.rs, src/services/install/ |
Verificação e instalação do Ollama por sistema: Windows (baixa OllamaSetup.exe e roda /silent), Linux (curl -fsSL https://ollama.com/install.sh | sh), macOS (baixa o zip e extrai em /Applications) |
src/crypto/ |
AES-256-GCM com nonce aleatório de 12 bytes prefixado ao ciphertext; chave em hex em <config do usuário>/OllaHubBackend/crypto_v2.key, carregada na inicialização |
src/ws/ |
WebSocket de eventos (/ws) e de chat (/ws/chat), montados sob o escopo /v2 |
src/middlewares/ |
JWT, CORS (origem única de ALLOWED_ORIGINS), logging de requisições e erros padronizados ({"error": "..."}) |
src/services/windows_permissions.rs |
Só no Windows: configuração de permissões na inicialização (veja o aviso abaixo) |
modelList.json |
Catálogo com 93 modelos (nome, descrição, capacidades, tamanhos, URL na biblioteca do Ollama); a API expõe name e description |
Warning
No Windows, o servidor mexe na configuração da máquina ao iniciar. Se estiver elevado (administrador), ele cria regras de entrada no Firewall para as portas
8080e11434(perfis Domain, Private e Public) e adiciona uma exclusão do Windows Defender para o próprio executável (Add-MpPreference). Sem privilégios de administrador apenas registra os avisos e segue.
Configuração
Copie .env.example para .env (carregado com dotenv na inicialização). Todas as variáveis são lidas em
src/config.rs e src/middlewares/:
| Variável | Padrão | Uso |
|---|---|---|
HOST |
127.0.0.1 |
Endereço de escuta |
PORT |
8080 |
Porta de escuta |
OLLAMA_BASE_URL |
http://localhost:11434 |
API do Ollama |
MODEL_LIST_PATH |
modelList.json |
Catálogo exposto em /v2/api/models |
JWT_SECRET |
changeme-dev-secret |
Segredo HS256 — troque; deve ser o mesmo de quem emite os tokens |
ALLOWED_ORIGINS |
http://localhost:3000 |
Única origem aceita pelo CORS (com credenciais) |
Executar localmente
Requisitos: toolchain Rust (edição 2021) e um Ollama acessível — ou use
POST /v2/api/ollama/install.
git clone https://git.evandro.dev.br/evandro/OllaHubBackend.git
cd OllaHubBackend
cp .env.example .env # ajuste JWT_SECRET e ALLOWED_ORIGINS
cargo run # sobe em http://127.0.0.1:8080
curl http://127.0.0.1:8080/health
curl http://127.0.0.1:8080/v2/api/ollama/check
curl -H "Authorization: Bearer <jwt>" http://127.0.0.1:8080/v2/api/models
cargo build --release # binário em target/release
cargo test # o repositório tem um teste: ida e volta da criptografia
Limitações conhecidas
- Usuários só em memória: o CRUD de
/api/v1/usersusa um repositório em memória; os dados somem ao reiniciar. /v2/wsnão envia eventos: o endpoint apenas ecoa mensagens e responde a pings. O envio de eventos ao cliente (PushEvent) existe no código mas nunca é acionado, e o progresso de instalações vai para outro broker.- Chat sem streaming incremental: o corpo da resposta do Ollama é lido por inteiro (timeout de 300 s) antes de as linhas serem repassadas, então os chunks chegam juntos ao fim da geração.
- Downloads sem progresso em tempo real:
pull_modeltambém lê a resposta inteira e só depois publica as linhas e o evento final. - Instalação do Ollama: roda instaladores baixados da internet no sistema operacional atual (Windows/Linux/macOS); sistemas não suportados retornam erro.
- Documentação defasada em um ponto:
docs/OLLAMA.mdcita rotas legadas (/ollama/install-check,/ollama/install) — as rotas atuais são/v2/api/ollama/checke/v2/api/ollama/install. SKIP_ANTIVIRUS_WARNINGS: consta no.env.example, mas nenhum código lê essa variável.- Firewall fixo na porta 8080: a regra criada no Windows usa
8080literal, mesmo comPORTdiferente.