From 5c7c416029b5a95ab47cf7256eceb20b4f06e768 Mon Sep 17 00:00:00 2001 From: Johan Jongsma Date: Mon, 2 Feb 2026 22:20:31 +0000 Subject: [PATCH] Add documentation, systemd service, test script - README with full API documentation - Systemd service file - Installation script - Test script for API verification - Environment file support for passwords --- README.md | 138 +++++++++++++++++++++++++++++++++ install.sh | 33 ++++++++ message-center.service | 15 ++++ test.sh | 56 +++++++++++++ ~/.message-center/cursors.json | 5 ++ 5 files changed, 247 insertions(+) create mode 100644 README.md create mode 100755 install.sh create mode 100644 message-center.service create mode 100755 test.sh create mode 100644 ~/.message-center/cursors.json diff --git a/README.md b/README.md new file mode 100644 index 0000000..7361394 --- /dev/null +++ b/README.md @@ -0,0 +1,138 @@ +# Message Center + +Unified API for messages from multiple sources (email, WhatsApp). + +## Features + +- **Unified Message Format**: All messages follow the same schema regardless of source +- **Connector Architecture**: Pluggable message sources +- **Cursor Tracking**: Track high-water mark per consumer for reliable processing +- **Replay Window**: Query messages from any time period with `?since=` +- **Actions**: Archive, delete, reply, and forward attachments to documents +- **Simple Webhooks**: Just notifies `{"event": "new"}` when new messages arrive + +## API Endpoints + +### Unified Messages + +| Endpoint | Method | Description | +|----------|--------|-------------| +| `/messages/new` | GET | Unseen messages from all sources | +| `/messages?since=24h` | GET | Messages from last 24 hours (supports h/d/w) | +| `/messages/{id}` | GET | Single message by ID | +| `/messages/ack` | POST | Advance cursor for a consumer | +| `/messages/{id}/archive` | POST | Archive message | +| `/messages/{id}/delete` | POST | Delete message | +| `/messages/{id}/reply` | POST | Reply to message | +| `/messages/{id}/to-docs` | POST | Save attachments to ~/documents/inbox/ | +| `/messages/{id}/attachments` | GET | List or download attachments | + +### Message Format + +```json +{ + "id": "proton:12345", + "source": "proton", + "from": "sender@example.com", + "from_name": "Sender Name", + "to": "recipient@example.com", + "timestamp": "2026-02-02T10:30:00Z", + "subject": "Hello World", + "body": "Message content...", + "attachments": [ + {"name": "doc.pdf", "mime": "application/pdf", "size": 12345} + ], + "seen": false +} +``` + +### Cursor/Acknowledgment + +```bash +# Acknowledge messages up to a timestamp +curl -X POST http://localhost:8025/messages/ack \ + -d '{"consumer": "james", "timestamp": "2026-02-02T12:00:00Z"}' +``` + +### Reply + +```bash +curl -X POST http://localhost:8025/messages/proton:12345/reply \ + -d '{"body": "Thanks for your message!"}' +``` + +### Forward to Documents + +```bash +# All attachments +curl -X POST http://localhost:8025/messages/proton:12345/to-docs + +# Specific attachments +curl -X POST http://localhost:8025/messages/proton:12345/to-docs \ + -d '{"attachments": ["invoice.pdf"]}' +``` + +## Configuration + +```yaml +server: + host: 127.0.0.1 + port: 8025 + +data_dir: ~/.message-center + +accounts: + proton: + host: 127.0.0.1 + port: 1143 + username: user@example.com + password: ${PROTON_BRIDGE_PASSWORD} + tls: starttls + watch: + - INBOX + smtp: + host: 127.0.0.1 + port: 1025 + +connectors: + whatsapp: + enabled: true + name: whatsapp + base_url: http://localhost:8030 + +webhook: + enabled: true + url: http://localhost:18789/hooks/messages +``` + +## Installation + +```bash +./install.sh +# Edit ~/.config/message-center.env with your passwords +systemctl --user start message-center +``` + +## Connectors + +### Email (IMAP) + +- Supports multiple accounts +- IDLE for real-time notifications +- Full message fetch with attachments +- Archive, delete, reply actions + +### WhatsApp + +- Wraps message-bridge HTTP API (port 8030) +- Polls for new messages (10s interval) +- Supports media attachments +- Reply via WhatsApp API + +## Legacy Endpoints + +For backwards compatibility with existing mail-bridge clients: + +- `GET /accounts` - List accounts +- `GET /accounts/{account}/mailboxes` - List folders +- `GET /accounts/{account}/messages` - List messages diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..3f2642a --- /dev/null +++ b/install.sh @@ -0,0 +1,33 @@ +#!/bin/bash +set -e + +# Build +echo "Building message-center..." +/usr/local/go/bin/go build -o message-center . + +# Install systemd service +echo "Installing systemd service..." +mkdir -p ~/.config/systemd/user/ +cp message-center.service ~/.config/systemd/user/ + +# Create env file if it doesn't exist +if [ ! -f ~/.config/message-center.env ]; then + echo "Creating ~/.config/message-center.env..." + cat > ~/.config/message-center.env << 'EOF' +# Proton Bridge passwords - get from pass store +PROTON_BRIDGE_PASSWORD= +JOHAN_BRIDGE_PASSWORD= +EOF + echo "Please edit ~/.config/message-center.env and add your passwords" +fi + +# Reload and enable +systemctl --user daemon-reload +systemctl --user enable message-center + +echo "" +echo "Installation complete!" +echo "" +echo "To start: systemctl --user start message-center" +echo "To check: systemctl --user status message-center" +echo "Logs: journalctl --user -u message-center -f" diff --git a/message-center.service b/message-center.service new file mode 100644 index 0000000..3bcc1bd --- /dev/null +++ b/message-center.service @@ -0,0 +1,15 @@ +[Unit] +Description=Message Center - Unified messaging API +After=network.target protonmail-bridge.service message-bridge.service +Wants=protonmail-bridge.service message-bridge.service + +[Service] +Type=simple +WorkingDirectory=/home/johan/dev/mail-bridge +EnvironmentFile=/home/johan/.config/message-center.env +ExecStart=/home/johan/dev/mail-bridge/message-center -config /home/johan/dev/mail-bridge/config.yaml +Restart=always +RestartSec=5 + +[Install] +WantedBy=default.target diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..4377b79 --- /dev/null +++ b/test.sh @@ -0,0 +1,56 @@ +#!/bin/bash +# Test script for Message Center API + +BASE_URL="${1:-http://localhost:8025}" + +echo "Testing Message Center at $BASE_URL" +echo "==================================" + +# Health check +echo -n "Health check: " +curl -sf "$BASE_URL/health" && echo " ✓" || echo " ✗" + +# List new messages +echo "" +echo "GET /messages/new:" +curl -sf "$BASE_URL/messages/new" | jq '.[0:2]' 2>/dev/null || echo "No messages or error" + +# List recent messages +echo "" +echo "GET /messages?since=1h:" +curl -sf "$BASE_URL/messages?since=1h" | jq 'length' 2>/dev/null | xargs -I{} echo "{} messages" || echo "Error" + +# Test since with different units +echo "" +echo "Testing since parameter parsing:" +for unit in "1h" "24h" "7d" "1w"; do + count=$(curl -sf "$BASE_URL/messages?since=$unit" | jq 'length' 2>/dev/null || echo "err") + echo " since=$unit: $count messages" +done + +# Get single message (if available) +echo "" +echo "GET /messages/{id} (first available):" +first_id=$(curl -sf "$BASE_URL/messages/new" | jq -r '.[0].id // empty' 2>/dev/null) +if [ -n "$first_id" ]; then + echo " Fetching: $first_id" + curl -sf "$BASE_URL/messages/$first_id" | jq '{id, source, from, subject}' 2>/dev/null || echo " Error" +else + echo " No messages available" +fi + +# Test cursor API +echo "" +echo "POST /messages/ack:" +curl -sf -X POST "$BASE_URL/messages/ack" \ + -H "Content-Type: application/json" \ + -d '{"consumer": "test", "timestamp": "2026-02-02T12:00:00Z"}' | jq . 2>/dev/null || echo "Error" + +# Legacy endpoints +echo "" +echo "GET /accounts (legacy):" +curl -sf "$BASE_URL/accounts" | jq . 2>/dev/null || echo "Error" + +echo "" +echo "==================================" +echo "Tests complete" diff --git a/~/.message-center/cursors.json b/~/.message-center/cursors.json new file mode 100644 index 0000000..f0dde19 --- /dev/null +++ b/~/.message-center/cursors.json @@ -0,0 +1,5 @@ +{ + "cursors": { + "test": "2026-02-02T12:00:00Z" + } +} \ No newline at end of file