117 lines
3.7 KiB
Markdown
117 lines
3.7 KiB
Markdown
# Voter-Uptime-Bot
|
|
|
|
|
|
A Discord bot that monitors the availability of web services and reports uptime statistics directly in your server. Built with `discord.py`, `aiohttp`, and `pydantic-settings`, it goes beyond simple HTTP checks — detecting Cloudflare intercept pages and validating real page content so you know your sites are genuinely reachable, not just returning a 200.
|
|
|
|
---
|
|
|
|
## Features
|
|
|
|
- **Periodic polling** — checks all configured sites every 15 minutes
|
|
- **Cloudflare intercept detection** — identifies challenge/block pages that return HTTP 200 but serve no real content
|
|
- **Keyword content validation** — confirms expected strings are present on the loaded page
|
|
- **Retry logic** — re-attempts checks on transient CF intercepts before marking a site degraded
|
|
- **Uptime history** — stores all check results in a local SQLite database
|
|
- **Discord slash commands** — view live status, 24-hour bars, and monthly summaries per site
|
|
|
|
---
|
|
|
|
## Commands
|
|
|
|
| Command | Description |
|
|
|---|---|
|
|
| `/uptime now` | Current status of all monitored sites |
|
|
| `/uptime day <site>` | 24-hour bar chart (🟩🟨🟥) with uptime % |
|
|
| `/uptime month <site>` | Current month summary, one square per day |
|
|
| `/uptime summarize` | Monthly uptime % for all sites at once |
|
|
|
|
---
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
app/
|
|
├── __init__.py
|
|
├── bot.py # Discord client, slash commands, polling task
|
|
├── checker.py # SiteChecker — HTTP, CF detection, keyword validation
|
|
├── config.py # Pydantic Settings — loads all config from .env
|
|
├── db.py # SQLite init, insert, and fetch helpers
|
|
└── utils.py # check_site wrapper, bar rendering, uptime maths
|
|
```
|
|
|
|
---
|
|
|
|
## Configuration
|
|
|
|
All configuration is managed via a `.env` file using `pydantic-settings`. Copy `.env.example` to `.env` and fill in your values.
|
|
|
|
```env
|
|
DISCORD_SECRET_KEY=your-bot-token-here
|
|
DISCORD_CLIENT_ID=123456789
|
|
DATABASE_PATH=uptime.db
|
|
|
|
MONITORED_SITES='[
|
|
{
|
|
"name": "MySite",
|
|
"url": "https://example.com",
|
|
"timeout_seconds": 10,
|
|
"expected_keywords": ["Login", "Vote"],
|
|
"max_retries": 1
|
|
}
|
|
]'
|
|
```
|
|
|
|
### Site config fields
|
|
|
|
| Field | Required | Default | Description |
|
|
|---|---|---|---|
|
|
| `name` | ✅ | — | Display name used in Discord |
|
|
| `url` | ✅ | — | Full URL to check |
|
|
| `timeout_seconds` | | `10` | Request timeout |
|
|
| `expected_status` | | `200` | Expected HTTP status code |
|
|
| `expected_keywords` | | `[]` | Strings that must appear in the page body |
|
|
| `max_retries` | | `1` | Extra attempts on CF intercept before marking degraded |
|
|
|
|
---
|
|
|
|
## How Checks Work
|
|
|
|
Each poll goes through three layers:
|
|
|
|
1. **HTTP status** — non-2xx/3xx responses are marked degraded or down
|
|
2. **Cloudflare detection** — response body is scanned for CF challenge fingerprints; a match is marked `degraded` even if status was 200
|
|
3. **Keyword validation** — any `expected_keywords` that are missing from the body mark the site `degraded`
|
|
|
|
Results are stored with a `detection_reason` (`cf_intercept`, `missing_keywords`, `http_503`, `timeout`, etc.) so you can query historical failure causes.
|
|
|
|
---
|
|
|
|
## Result States
|
|
|
|
| State | Emoji | Meaning |
|
|
|---|---|---|
|
|
| `up` | 🟩 | HTTP OK, no CF intercept, all keywords present, latency < 3s |
|
|
| `degraded` | 🟨 | Reachable but CF intercept, missing content, slow, or 5xx |
|
|
| `down` | 🟥 | Timeout, connection failure, SSL error, or unexpected status |
|
|
|
|
---
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
pip install -r requirements.txt
|
|
```
|
|
|
|
Run the bot:
|
|
|
|
```bash
|
|
python -m app.bot
|
|
```
|
|
|
|
---
|
|
|
|
## Requirements
|
|
|
|
- Python 3.11+
|
|
- A Discord bot token with the `applications.commands` scope and `bot` scope enabled
|
|
- The bot must be invited to your server with slash command permissions |