Quick Start¶
Get up and running with Mototli in minutes. This guide covers three common scenarios.
Scenario 1: Browse Gopherspace¶
Use the CLI to explore existing gopher servers.
Step 1: Fetch a directory listing¶
You'll see a formatted directory listing:
[DIR] /gopher Welcome to Floodgap
[TXT] /gopher/glog The Gopher Gazette
[DIR] /v2 Veronica-2 Search
[INF] ────────────────────
[INF] Last updated: 2024-01
Step 2: Fetch a text file¶
Step 3: Get Gopher+ attributes¶
Verbose output
Add --verbose to see the raw protocol exchange:
Scenario 2: Serve a Gopherhole¶
Host your own gopher content in under a minute.
Step 1: Create a content directory¶
Step 2: Add a welcome file¶
Create index.txt:
Step 3: Start the server¶
You'll see:
Starting Gopher server...
Document root: /path/to/my-gopherhole
Listening on: localhost:7070
Gopher+ enabled: Yes
Step 4: Browse your site¶
In another terminal:
Default port
Gopher's default port is 70, which requires root privileges on Unix systems.
Use --port 7070 or another high port for development.
Scenario 3: Use the Python Client¶
Integrate Gopher access into your Python applications.
Step 1: Create a script¶
Create browse.py:
import asyncio
from mototli.client import GopherClient
async def main():
async with GopherClient(timeout=30.0) as client:
# Fetch a directory listing
response = await client.get("gopher.floodgap.com", "/")
print("=== Directory Listing ===")
for item in response.items:
if item.item_type.is_informational:
print(f" {item.display_text}")
else:
print(f"[{item.item_type.value}] {item.display_text}")
print(f" -> {item.selector}")
asyncio.run(main())
Step 2: Run it¶
Step 3: Fetch text content¶
async def fetch_text():
async with GopherClient() as client:
response = await client.get_text("gopher.floodgap.com", "/gopher/welcome")
print(response.content.decode())
asyncio.run(fetch_text())
Step 4: Handle binary files¶
async def fetch_binary():
async with GopherClient() as client:
response = await client.get_binary("gopher.floodgap.com", "/gopher/logo.gif")
with open("logo.gif", "wb") as f:
f.write(response.content)
print(f"Saved {len(response.content)} bytes")
asyncio.run(fetch_binary())
Common Issues¶
Connection refused¶
Solution: The server isn't running, or you need to specify the correct port:
Timeout errors¶
Solution: The server may be slow or unreachable. Increase the timeout:
Port permission denied¶
Solution: Port 70 requires root privileges. Use a high port:
Recommended Learning Paths¶
Choose based on your goals:
I want to host a gopherhole¶
- Your First Gopherhole - Complete server tutorial
- Configure Server - TOML configuration
- Setup CGI - Dynamic content
I want to build a gopher client¶
- Building a Client - Client tutorial
- Fetch Resources - Advanced fetching
- Client API - Full API reference
I want to understand the protocol¶
- Gopher Protocol - Protocol deep-dive
- Gopher+ Extensions - RFC 4266
- Item Types - Type reference
Getting Help¶
- Issues: GitHub Issues
- Discussions: GitHub Discussions