Blahg#
A Rust-based ATProtocol AppView for rendering personal blog content from the ATProtocol network.
Overview#
Blahg is a high-performance blog engine that consumes ATProtocol records to create a traditional blog-like reading experience. It processes both custom blog post records (tools.smokesignal.blahg.content.post) and standard ATProtocol social media posts (app.bsky.feed.post), providing a unified interface for content discovery and presentation.
Features#
Core Functionality#
- Real-time Event Processing: Consumes ATProtocol Jetstream events for live content updates
- Multi-Format Content Support: Handles markdown, HTML, and plain text content
- Custom Lexicon Support: Implements
tools.smokesignal.blahg.content.postschema for rich blog posts - Post Import Tool: Command-line utility for importing individual posts via AT-URI
- Identity Resolution: Automatic DID and handle resolution with caching
- Post Interactions: Tracks likes, reposts, and other engagement metrics
Storage & Infrastructure#
- Multi-Database Support: Both PostgreSQL and SQLite backends supported
- Flexible Content Storage: Filesystem and S3-compatible object storage
- Efficient Caching: LRU caching for posts, identities, and content
- Template Engine: Minijinja-based templating with hot-reload support during development
- Markdown Rendering: Comrak-powered markdown with syntax highlighting
Web Interface#
- Responsive Design: Clean, accessible blog interface with Pico.css
- SEO Optimized: Proper meta tags, OpenGraph support, and canonical URLs
- Post Interactions: Display engagement metrics and interaction history
- Static Asset Serving: Efficient static file serving with proper caching
Architecture#
Blahg consists of two main components:
- blahg: The main server application that runs the web interface and processes real-time events
- blahg-import: A command-line tool for importing individual posts from AT-URIs
Data Flow#
- ATProtocol events are consumed via Jetstream
- Relevant records are filtered and processed
- Post content and attachments are stored
- Web interface serves rendered content with caching
Dependencies#
This project uses the following atproto crates:
atproto-identity- Identity resolution and verificationatproto-record- Record handling and parsingatproto-client- ATProtocol client functionalityatproto-jetstream- Real-time event streaming
Installation#
Prerequisites#
- Rust 1.87 or higher
- Cargo
- PostgreSQL or SQLite (depending on your database choice)
Building from Source#
git clone https://github.com/yourusername/blahg.git
cd blahg
cargo build --release
Docker#
docker build -t blahg .
docker run -p 8080:8080 blahg
Usage#
Running the Server#
# Run with default configuration
./target/release/blahg
# Run with custom configuration via environment variables
BLAHG_AUTHOR="did:plc:example" \
BLAHG_DATABASE_URL="postgresql://user:pass@localhost/blahg" \
BLAHG_ATTACHMENT_STORAGE="s3://your-bucket/attachments/" \
./target/release/blahg
Importing Posts#
# Import a single post
./target/release/blahg-import at://did:plc:example/tools.smokesignal.blahg.content.post/abc123
# Import multiple posts
./target/release/blahg-import \
at://did:plc:example/tools.smokesignal.blahg.content.post/abc123 \
at://did:plc:example/tools.smokesignal.blahg.content.post/def456
Configuration#
Configuration is managed via environment variables:
Core Settings#
BLAHG_AUTHOR: Your ATProtocol DID (required)BLAHG_EXTERNAL_BASE: Base URL for your blog (default:http://localhost:8080)BLAHG_HTTP_PORT: HTTP server port (default:8080)
Database#
BLAHG_DATABASE_URL: Database connection string- SQLite:
sqlite://blahg.db - PostgreSQL:
postgresql://user:pass@localhost/blahg
- SQLite:
Storage#
BLAHG_ATTACHMENT_STORAGE: Content storage location- Filesystem:
./attachments - S3:
s3://bucket/prefix/
- Filesystem:
ATProtocol#
BLAHG_ENABLE_JETSTREAM: Enable real-time event processing (default:true)BLAHG_JETSTREAM_CURSOR_PATH: Path to store Jetstream cursor (optional)BLAHG_PLC_HOSTNAME: PLC directory hostname (default:plc.directory)
HTTP Client#
BLAHG_USER_AGENT: HTTP client user agentBLAHG_HTTP_CLIENT_TIMEOUT: HTTP client timeout (default:10s)BLAHG_CERTIFICATE_BUNDLES: Additional CA certificates (comma-separated paths)
Development#
Feature Flags#
Blahg supports several feature flags for different deployment scenarios:
sqlite: Enable SQLite database support (default: enabled)postgres: Enable PostgreSQL database support (default: enabled)s3: Enable S3-compatible object storage (default: enabled)embed: Embed templates in binary for production (default: disabled)reload: Enable template hot-reloading for development (default: enabled)
Development Environment#
# Run in development mode with hot-reloading
cargo run
# Run with specific features
cargo run --no-default-features --features "sqlite,reload"
Running Tests#
cargo test
Linting and Type Checking#
cargo clippy
cargo check
Building for Production#
# Build with embedded templates
cargo build --release --no-default-features --features "embed,postgres,s3"
API Endpoints#
Blahg provides a simple web interface with the following endpoints:
GET /: Homepage with list of all postsGET /posts/{slug}: Individual post pageGET /posts/{slug}/{collection}: Post interaction references (likes, reposts, etc.)GET /static/*: Static asset serving (CSS, JS, images)
ATProtocol Lexicon#
Blahg implements the tools.smokesignal.blahg.content.post lexicon for rich blog posts:
{
"title": "string", // Post title (max 200 graphemes)
"content": "blob", // Post content (markdown/HTML/text, max 1MB)
"publishedAt": "datetime", // Publication timestamp
"langs": ["string"], // Language codes (max 3)
"attachments": [ // Optional image attachments
{
"content": "blob", // Image blob (max 3MB)
"alt": "string" // Alt text for accessibility
}
]
}
Contributing#
Contributions are welcome! Please feel free to submit a Pull Request.
License#
Blahg is open source software released under the MIT License.