### Mototli Development Setup Source: https://github.com/alanbato/mototli/blob/main/docs/installation.md Sets up the development environment for contributing to Mototli. This includes cloning the repository, installing all dependencies (including development tools) using uv, and running tests and linters. ```bash # Clone the repository git clone https://github.com/alanbato/mototli.git cd mototli # Install all dependencies (including dev tools) uv sync # Run tests uv run pytest # Run linting uv run ruff check . # Run type checking uv run mypy src/ ``` -------------------------------- ### Test CGI Script with Mototli CLI Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/setup-cgi.md Starts the Mototli server and fetches the output of a CGI script using the Mototli CLI. ```bash mototli serve my-gopherhole --port 7070 mototli text localhost:7070 /cgi-bin/hello.cgi ``` -------------------------------- ### Install Mototli from Source Source: https://github.com/alanbato/mototli/blob/main/docs/installation.md Installs the latest development version of Mototli directly from its GitHub repository. This involves cloning the repository and then using uv to synchronize dependencies. ```bash git clone https://github.com/alanbato/mototli.git cd mototli uv sync ``` -------------------------------- ### Python CGI Script Example Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/setup-cgi.md A Python CGI script that displays various Gopher environment variables, including selector, query string, server details, and client information. ```python #!/usr/bin/env python3 import os import sys print("=== Gopher CGI Info ===") print() print(f"Selector: {os.environ.get('SELECTOR', '(none)')}") print(f"Query: {os.environ.get('QUERY_STRING', '(none)')}") print(f"Server: {os.environ.get('SERVER_NAME', '?')}:{os.environ.get('SERVER_PORT', '?')}") print(f"Client: {os.environ.get('REMOTE_HOST', '?')}") print(f"Gopher+: {'Yes' if os.environ.get('GOPHER_PLUS') == '1' else 'No'}") print() print("=== All Environment ===") for key, value in sorted(os.environ.items()): if key.startswith(('GOPHER', 'SERVER', 'REMOTE', 'QUERY', 'SELECTOR', 'SCRIPT', 'DOCUMENT')): print(f"{key}={value}") ``` -------------------------------- ### Verify Mototli Installation Source: https://github.com/alanbato/mototli/blob/main/docs/installation.md Checks the installed version of Mototli and demonstrates fetching a resource from a public gopher server. This confirms that the installation was successful and the tool is functional. ```bash mototli version mototli get gopher.floodgap.com ``` -------------------------------- ### Serve a Gopherhole with Mototli CLI Source: https://github.com/alanbato/mototli/blob/main/docs/quickstart.md Set up and run your own Gopher server using Mototli. This involves creating a content directory, adding an index file, and starting the server on a specified port. You can then browse your Gopherhole locally. ```bash mkdir my-gopherhole cd my-gopherhole # Create index.txt with content mototli serve . --port 7070 mototli get localhost:7070 ``` -------------------------------- ### Configure and Start Gopher Server with ServerConfig (Python) Source: https://github.com/alanbato/mototli/blob/main/docs/reference/api/server.md Example demonstrating how to configure and start a Gopher server using the ServerConfig class for detailed settings. It includes host, port, hostname, document root, Gopher+, admin details, and runs indefinitely until stopped. ```python import asyncio from mototli.server import GopherServer, ServerConfig from pathlib import Path config = ServerConfig( host="0.0.0.0", port=7070, hostname="gopher.example.com", document_root=Path("/var/gopher"), gopher_plus=True, admin_name="Admin", admin_email="admin@example.com" ) async def main(): server = GopherServer(config) await server.start() try: await asyncio.Event().wait() # Run forever finally: await server.stop() asyncio.run(main()) ``` -------------------------------- ### Create CGI Directory Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/setup-cgi.md Creates the necessary directory structure for CGI scripts. ```bash mkdir -p my-gopherhole/cgi-bin ``` -------------------------------- ### Start Mototli Server with Configuration File Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/configure-server.md Launches the Mototli server using a specified TOML configuration file. This command applies all settings defined within the configuration file to the running server. ```bash mototli serve --config server.toml ``` -------------------------------- ### Troubleshoot Import Errors Source: https://github.com/alanbato/mototli/blob/main/docs/installation.md Guides users on resolving import errors when Mototli can be run but not imported as a library. This involves verifying the correct Python environment and checking the installed package details. ```bash # Ensure you're in the correct environment which python pip show mototli ``` -------------------------------- ### Start Mototli Gopher+ Server Source: https://github.com/alanbato/mototli/blob/main/docs/tutorials/understanding-gopher-plus.md Shows how to start the Mototli Gopher+ server from the command line, specifying the content directory and port. Gopher+ is enabled by default. ```bash mototli serve ./my-gopherhole --port 7070 ``` -------------------------------- ### Install Mototli using uv Source: https://github.com/alanbato/mototli/blob/main/docs/installation.md Installs Mototli using the uv package manager. This method is recommended for its speed and reliability. It can be added to an existing project or installed globally as a tool. ```bash # Add to an existing project uv add mototli # Or install globally uv tool install mototli ``` -------------------------------- ### Mototli Complete Server Configuration Example (TOML) Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/configure-server.md A comprehensive TOML configuration file demonstrating the integration of server, handler, Gopher+, and limits settings for a fully functional Mototli server. ```toml # server.toml - Complete Mototli configuration [server] host = "0.0.0.0" port = 70 hostname = "gopher.example.com" document_root = "/var/gopher" [handlers] enable_directory_listing = true default_indices = ["gophermap", "index.gph", "index.txt"] max_file_size = 104857600 cgi_extensions = [".cgi", ".sh", ".py"] cgi_directories = ["cgi-bin"] [gopher_plus] enabled = true admin_name = "Server Admin" admin_email = "admin@example.com" [limits] request_timeout = 30.0 cgi_timeout = 30.0 ``` -------------------------------- ### Python CGI Input Validation Example Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/setup-cgi.md Demonstrates secure input handling for CGI scripts by validating the QUERY_STRING using regular expressions to allow only alphanumeric characters and spaces. ```python #!/usr/bin/env python3 import os import re query = os.environ.get('QUERY_STRING', '') # Validate input - only allow alphanumeric and spaces if not re.match(r'^[ws]*$', query): print("Error: Invalid search query") exit(1) # Safe to use query now print(f"Searching for: {query}") ``` -------------------------------- ### Mototli Async Server Example in Python Source: https://github.com/alanbato/mototli/blob/main/docs/index.md Shows how to run a basic Mototli Gopher server using asyncio, configured to serve content from a specified local directory. Ensure the 'mototli' library is installed and the document root directory exists. ```python import asyncio from mototli.server import run_server asyncio.run(run_server(document_root="./gopherhole")) ``` -------------------------------- ### Troubleshoot Permission Errors Source: https://github.com/alanbato/mototli/blob/main/docs/installation.md Offers solutions for permission errors encountered during Mototli installation or execution. It suggests using uv or pipx for system-wide installs or employing virtual environments. ```bash # Use 'uv' or 'pipx' instead of 'pip' for system-wide installs # Or use a virtual environment: 'python -m venv .venv && source .venv/bin/activate' ``` -------------------------------- ### Mototli CLI Usage Examples Source: https://github.com/alanbato/mototli/blob/main/docs/index.md Illustrates common command-line operations for the Mototli tool, including fetching resources from a Gopher server and serving local files from a directory on a specified port. These commands assume the 'mototli' package is installed and accessible in the system's PATH. ```bash # Browse a gopher server mototli get gopher.floodgap.com # Serve a local directory mototli serve ./my-gopherhole --port 7070 ``` -------------------------------- ### Install Mototli using pipx Source: https://github.com/alanbato/mototli/blob/main/docs/installation.md Installs Mototli as a command-line interface (CLI) tool in an isolated environment using pipx. This ensures that Mototli and its dependencies do not interfere with other Python projects. ```bash pipx install mototli ``` -------------------------------- ### Write a Simple Bash CGI Script Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/setup-cgi.md A basic CGI script written in Bash that outputs a greeting, current time, and request selector. ```bash #!/bin/bash echo "Hello from CGI!" echo "" echo "Current time: $(date)" echo "Your request: $SELECTOR" ``` -------------------------------- ### Install Mototli Package Source: https://github.com/alanbato/mototli/blob/main/README.md Instructions for installing the Mototli library using package managers uv and pip. It's recommended to use uv for installation. ```bash # Using uv (recommended) uv add mototli # Using pip pip install mototli ``` -------------------------------- ### Make CGI Script Executable Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/setup-cgi.md Sets the execute permission for a CGI script, allowing it to be run by the server. ```bash chmod +x my-gopherhole/cgi-bin/hello.cgi ``` -------------------------------- ### Python CGI Script for Directory Listings Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/setup-cgi.md Generates dynamic Gophermaps by listing files and directories in the DOCUMENT_ROOT, differentiating between directories and specific file types. ```python #!/usr/bin/env python3 import os from datetime import datetime print(f"iDynamic Directory Listing\tfake\t(NULL)\t0") print(f"iGenerated: {datetime.now()}\tfake\t(NULL)\t0") print(f"i\tfake\t(NULL)\t0") doc_root = os.environ.get('DOCUMENT_ROOT', '.') for item in sorted(os.listdir(doc_root)): path = os.path.join(doc_root, item) if os.path.isdir(path): print(f"1{item}\t/{item}\tlocalhost\t7070") elif item.endswith(('.txt', '.md')): print(f"0{item}\t/{item}\tlocalhost\t7070") ``` -------------------------------- ### Install Mototli using pip Source: https://github.com/alanbato/mototli/blob/main/docs/installation.md Installs Mototli directly into the current Python environment using pip. This method is suitable for users who manage their project environments manually. ```bash pip install mototli ``` -------------------------------- ### Run Gopher Server (Python) Source: https://github.com/alanbato/mototli/blob/main/docs/reference/api/server.md Quick start example to run a Gopher server serving the current directory on a specified port. Uses Python's asyncio for asynchronous operation. ```python import asyncio from mototli.server import run_server # Serve current directory on port 7070 asyncio.run(run_server(document_root=".", port=7070)) ``` -------------------------------- ### Generate Mototli Server Configuration Template Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/configure-server.md Use the `--init` flag with the `mototli serve` command to generate a TOML configuration template. This template includes all available options with their default values, serving as a starting point for customization. ```bash mototli serve --init > server.toml ``` -------------------------------- ### Fetch Gopherspace Directory Listing with Python Client Source: https://github.com/alanbato/mototli/blob/main/docs/quickstart.md Utilize the `mototli.client.GopherClient` in Python to asynchronously fetch and parse directory listings from a Gopher server. The client handles connection management and response parsing. ```python import asyncio from mototli.client import GopherClient async def main(): async with GopherClient(timeout=30.0) as client: 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()) ``` -------------------------------- ### Complete Gophermap Example Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/directory-listings.md A comprehensive gophermap example showcasing various elements: informational text, ASCII art headers, links to local files and directories, a search form, external links, and a footer. It illustrates the full range of customization options. ```gophermap i╔═══════════════════════════════════╗ fake (NULL) 0 i║ Welcome to My Gopherhole ║ fake (NULL) 0 i╚═══════════════════════════════════╝ fake (NULL) 0 i fake (NULL) 0 iHello! This is my personal gopher site. fake (NULL) 0 iLast updated: January 2025 fake (NULL) 0 i fake (NULL) 0 i--- Navigation --- fake (NULL) 0 i fake (NULL) 0 0About Me /about.txt localhost 7070 1Blog Posts /blog localhost 7070 1Projects /projects localhost 7070 9Download Archive /files/archive.tar.gz localhost 7070 i fake (NULL) 0 i--- Search --- fake (NULL) 0 i fake (NULL) 0 7Search this site /cgi-bin/search.py localhost 7070 i fake (NULL) 0 i--- External Links --- fake (NULL) 0 i fake (NULL) 0 1Floodgap Gopher / gopher.floodgap.com 70 hWeb Homepage URL:https://example.com (NULL) 0 i fake (NULL) 0 i--- fake (NULL) 0 iPowered by Mototli fake (NULL) 0 ``` -------------------------------- ### Fetch Binary Files with Python Client Source: https://github.com/alanbato/mototli/blob/main/docs/quickstart.md Asynchronously download binary files, such as images, from a Gopher server using `GopherClient.get_binary`. The raw byte content can then be saved to a local file. ```python import asyncio from mototli.client import GopherClient 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()) ``` -------------------------------- ### Troubleshoot 'Command not found' Error Source: https://github.com/alanbato/mototli/blob/main/docs/installation.md Provides steps to resolve the 'command not found' error after installing Mototli. This typically involves ensuring the installation directory is in the system's PATH or updating shell configurations. ```bash # Ensure the installation location is in your PATH # For pipx, run 'pipx ensurepath' # For uv tool, run 'uv tool update-shell' ``` -------------------------------- ### start_server convenience function Source: https://github.com/alanbato/mototli/blob/main/docs/reference/api/server.md Another convenience function for starting the Gopher server, potentially offering more control than `run_server`. ```APIDOC ## start_server ### Description Convenience function to start the Gopher server. ### Function `mototli.server.start_server()` ### Usage Example ```python import asyncio from mototli.server import start_server # Assuming server configuration is set elsewhere or defaults are used asyncio.run(start_server()) ``` ``` -------------------------------- ### CLI - Browse Gopherspace Commands Source: https://context7.com/alanbato/mototli/llms.txt Provides various command-line examples for browsing Gopherspace using the 'mototli' tool. Covers fetching directory listings, specific text files, searching, downloading binary files with output redirection, getting Gopher+ attributes, verbose output, and custom port/timeout settings. No specific dependencies mentioned beyond the 'mototli' CLI tool. ```bash # Fetch directory listing mototli get gopher.floodgap.com # Fetch specific text file mototli text gopher.floodgap.com /gopher/welcome # Search gopherspace mototli get gopher.floodgap.com /v2/vs --search "python" # Download binary file mototli get gopher.example.com /files/data.zip -o mydata.zip # Download to specific directory and open mototli get gopher.example.com /image.png -d ~/Downloads --open # Get Gopher+ attributes mototli attrs gopher.example.com /about # Verbose output with full details mototli get gopher.floodgap.com -v # Pipe binary to stdout mototli get gopher.example.com /archive.tar.gz --stdout | tar -xz # Custom port and timeout mototli get gopher.example.com:7070 / --timeout 60 ``` -------------------------------- ### Load Environment-Specific Mototli Configurations Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/configure-server.md Demonstrates how to load different configuration files for various environments (e.g., development, production) by specifying distinct TOML files with the `--config` flag. ```bash # Development mototli serve --config server.dev.toml # Production mototli serve --config server.prod.toml ``` -------------------------------- ### Browse Gopherspace with Mototli CLI Source: https://github.com/alanbato/mototli/blob/main/docs/quickstart.md Use the Mototli command-line interface to fetch directory listings, text files, and Gopher+ attributes from a specified Gopher server. The `--verbose` flag can be used to see the raw protocol exchange. ```bash mototli get gopher.floodgap.com mototli text gopher.floodgap.com /gopher/welcome mototli attrs gopher.floodgap.com /gopher mototli get gopher.floodgap.com --verbose ``` -------------------------------- ### Debug CGI Scripts via Shell Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/setup-cgi.md Provides a method to debug CGI scripts by manually setting environment variables and executing the script directly in the shell. ```bash # Set environment variables export SELECTOR="/cgi-bin/test.cgi" export QUERY_STRING="test query" export SERVER_NAME="localhost" export SERVER_PORT="7070" # Run the script ./cgi-bin/test.cgi ``` -------------------------------- ### Python: Preview File Size Before Download Source: https://github.com/alanbato/mototli/blob/main/docs/explanation/gopher-plus.md Python code example to check a file's size using Gopher+ attributes before initiating a full download, preventing unnecessary large transfers. ```python # Check size before downloading a large file attrs = await client.get_attributes(host, "/large-archive.zip") if attrs.info and attrs.info.size > 100_000_000: print("Warning: File is over 100MB") if not confirm(): return response = await client.get_binary(host, "/large-archive.zip") ``` -------------------------------- ### Python CGI Script for Search Queries Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/setup-cgi.md Handles Gopher type 7 search queries by retrieving the query string from the environment and simulating search results. ```python #!/usr/bin/env python3 import os query = os.environ.get('QUERY_STRING', '') if not query: print("Enter a search term:") print("") print("Usage: Select this item and enter your query") else: print(f"Searching for: {query}") print("") # Simulate search results results = [ f"Result 1 for '{query}'", f"Result 2 for '{query}'", f"Result 3 for '{query}'", ] for result in results: print(result) ``` -------------------------------- ### Gopher+ Directory Listing Format Example Source: https://github.com/alanbato/mototli/blob/main/docs/explanation/gopher-plus.md Shows the format of Gopher+ directory entries, highlighting the '+' indicator at the end of the line, which signifies that the item supports Gopher+ queries and features. ```text 0Document /doc.txt server.example 70 + 1Archive /archive server.example 70 + ``` -------------------------------- ### Python Server: Run a Gopherhole Server Source: https://github.com/alanbato/mototli/blob/main/README.md An asynchronous Python example showing how to run a Gopherhole server using Mototli. This function starts the server, specifying the root directory for documents and the port to listen on. ```python import asyncio from mototli.server import run_server asyncio.run(run_server(document_root="./gopherhole", port=7070)) ``` -------------------------------- ### Serve Directory with Auto-Generated Listing (Bash) Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/directory-listings.md This command creates a directory, adds a simple text file, and starts the Mototli server. When accessed, Mototli will automatically generate a directory listing. ```bash mkdir my-gopherhole echo "Hello" > my-gopherhole/hello.txt mototli serve my-gopherhole --port 7070 ``` -------------------------------- ### Load Server Configuration from TOML File (Python) Source: https://github.com/alanbato/mototli/blob/main/docs/reference/api/server.md Demonstrates loading Gopher server configuration directly from a TOML file using ServerConfig.from_toml(). This simplifies configuration management for complex setups. ```python import asyncio from mototli.server import GopherServer, ServerConfig config = ServerConfig.from_toml("server.toml") async def main(): server = GopherServer(config) await server.start() await asyncio.Event().wait() asyncio.run(main()) ``` -------------------------------- ### Mototli Server Startup Verification Message Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/configure-server.md The server startup message provides a summary of the applied configuration settings, allowing users to quickly verify that the server is running with the intended parameters. ```text Starting Gopher server... Document root: /var/gopher Listening on: 0.0.0.0:70 Hostname: gopher.example.com Gopher+ enabled: Yes Admin: Server Admin ``` -------------------------------- ### Gophermap Entry Format (Example) Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/directory-listings.md Demonstrates the structure of a gophermap file, where each line defines an item with its type, display text, selector, host, and port. Literal tab characters are crucial for separation. ```gophermap iWelcome to my site! fake (NULL) 0 i fake (NULL) 0 0Read the welcome message /hello.txt localhost 7070 ``` -------------------------------- ### Programmatically Configure and Start Mototli Server in Python Source: https://github.com/alanbato/mototli/blob/main/docs/reference/configuration.md Shows how to create and configure a Mototli server instance programmatically in Python using the `ServerConfig` class. This allows for dynamic configuration before initializing the `GopherServer`. ```python from mototli.server import ServerConfig, GopherServer from pathlib import Path config = ServerConfig( host="0.0.0.0", port=7070, hostname="localhost", document_root=Path("./content"), gopher_plus=True, admin_name="Admin", admin_email="admin@example.com" ) server = GopherServer(config) ``` -------------------------------- ### Python: Gopher+ Content Negotiation Source: https://github.com/alanbato/mototli/blob/main/docs/explanation/gopher-plus.md Python example illustrating content negotiation using Gopher+. It first retrieves available views for a document and then requests a specific format, such as 'text/plain'. ```python # Get available formats attrs = await client.get_attributes(host, "/document") # Find preferred format for view in attrs.views: if view.content_type == "text/plain": response = await client.get_with_view(host, "/document", "text/plain") break ``` -------------------------------- ### Test Client-Server Integration (Python) Source: https://github.com/alanbato/mototli/blob/main/docs/explanation/architecture.md An asynchronous integration test function that starts a test server, makes a client request, and then stops the server. It uses `start_test_server` and `GopherClient`. ```python from mototli.client import GopherClient async def test_client_server(): server = await start_test_server() # Assuming this function exists async with GopherClient() as client: response = await client.get("localhost", "/") await server.stop() ``` -------------------------------- ### Mototli Development Workflow Source: https://github.com/alanbato/mototli/blob/main/README.md Commands for setting up and managing the Mototli project during development. This includes cloning the repository, installing dependencies, running tests, linting, type checking, and building documentation. ```bash # Clone and install git clone https://github.com/alanbato/mototli.git cd mototli uv sync # Run tests uv run pytest # Run linting uv run ruff check . # Run type checking uv run mypy src/ # Build docs locally uv run mkdocs serve ``` -------------------------------- ### Python Client: Browse Gopherspace Source: https://github.com/alanbato/mototli/blob/main/README.md An asynchronous Python example demonstrating how to use the Mototli GopherClient to fetch and print items from a gopherspace directory listing. It utilizes asyncio for non-blocking operations. ```python import asyncio from mototli.client import GopherClient async def main(): async with GopherClient() as client: response = await client.get("gopher.floodgap.com", "/") for item in response.items: print(f"[{item.item_type.value}] {item.display_text}") asyncio.run(main()) ``` -------------------------------- ### Create Project Directory and Client File Source: https://github.com/alanbato/mototli/blob/main/docs/tutorials/building-a-client.md Sets up the project structure by creating a new directory for the gopher client and initializing a basic Python file with asynchronous main function and Mototli client import. This step verifies the initial setup. ```bash mkdir gopher-client cd gopher-client ``` ```bash python client.py ``` -------------------------------- ### Mototli CLI Error Handling: Connection Refused Source: https://github.com/alanbato/mototli/blob/main/docs/quickstart.md Example of a 'Connection refused' error when trying to connect to a Gopher server, typically indicating the server is not running or on the wrong port. The solution suggests specifying the correct port. ```bash # Error example: # Error: Connection refused to localhost:70 # Solution: mototli get localhost:7070 ``` -------------------------------- ### start_server - Quick Server Launch Source: https://context7.com/alanbato/mototli/llms.txt A convenience function for launching a Gopher server with minimal configuration. It utilizes 'asyncio', 'pathlib', and 'mototli.server.start_server'. This function simplifies server setup by accepting key parameters directly, including host, port, document root, and Gopher Plus settings. It includes built-in Ctrl+C handling for graceful shutdown. ```python import asyncio from pathlib import Path from mototli.server import start_server async def quick_server(): await start_server( host="0.0.0.0", port=7070, document_root="/var/gopher", hostname="gopher.example.com", enable_directory_listing=True, gopher_plus=True, admin_name="Admin", admin_email="admin@example.com" ) try: asyncio.run(quick_server()) except KeyboardInterrupt: print("\nServer stopped") ``` -------------------------------- ### Configure Gopher Server with TOML (Python) Source: https://github.com/alanbato/mototli/blob/main/docs/explanation/architecture.md Demonstrates how to load server configuration from a TOML file and initialize the Gopher server. It requires a `server.toml` file with the appropriate settings. ```python from mototli.server import ServerConfig, GopherServer config = ServerConfig.from_toml("server.toml") server = GopherServer(config) ``` -------------------------------- ### Gopher+ Attribute Blocks Examples Source: https://github.com/alanbato/mototli/blob/main/docs/explanation/gopher-plus.md Illustrates the structure and content of Gopher+ attribute blocks, including +INFO for basic item details, +ADMIN for server administrator information, +VIEWS for available content representations, +ABSTRACT for a short description, and +ASK for interactive form elements. ```text +INFO: 0document.txt /document.txt server.example 70 + ``` ```text +ADMIN: Admin: Site Admin Mod-Date: <20240115120000> ``` ```text +VIEWS: text/plain: <15k> text/html: <25k> application/pdf: <150k> ``` ```text +ABSTRACT: This document explains the Gopher+ protocol extensions and how to use them effectively. ``` ```text +ASK: Ask: What is your name? Choose: Preferred format text html pdf ``` -------------------------------- ### Capture Mototli Server Logs Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/setup-cgi.md Redirects the output of the Mototli server, including errors, to a log file for debugging purposes. ```bash mototli serve my-gopherhole --port 7070 2>&1 | tee server.log ``` -------------------------------- ### Configure Zsh Shell Completion for Mototli Source: https://github.com/alanbato/mototli/blob/main/docs/installation.md Enables shell completion for Mototli commands in the Zsh shell. This enhances usability by offering context-aware suggestions for commands and their options. ```bash # Add to ~/.zshrc eval "$(mototli --show-completion zsh)" ``` -------------------------------- ### Initialize Python Client and Connect to Gopherspace Source: https://github.com/alanbato/mototli/blob/main/docs/tutorials/building-a-client.md Demonstrates how to initialize the Mototli GopherClient within an asynchronous context manager. It shows how to set a timeout and fetch the root directory of a gopher server, printing the number of items found. This snippet focuses on basic connection and retrieval. ```python import asyncio from mototli.client import GopherClient async def main(): # Create a client with a 30-second timeout async with GopherClient(timeout=30.0) as client: # Fetch the root directory response = await client.get("gopher.floodgap.com", "/") print(f"Fetched {len(response.items)} items") if __name__ == "__main__": asyncio.run(main()) ``` -------------------------------- ### Fetch Text Content with Python Client Source: https://github.com/alanbato/mototli/blob/main/docs/quickstart.md Asynchronously retrieve text file content from a Gopher server using the `GopherClient.get_text` method. The response content is decoded into a string. ```python import asyncio from mototli.client import GopherClient 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()) ``` -------------------------------- ### Configure Bash Shell Completion for Mototli Source: https://github.com/alanbato/mototli/blob/main/docs/installation.md Enables shell completion for Mototli commands in the Bash shell. This improves user experience by providing command and argument suggestions as you type. ```bash # Add to ~/.bashrc eval "$(mototli --show-completion bash)" ``` -------------------------------- ### Configure Mototli Gopher+ Server with TOML Source: https://github.com/alanbato/mototli/blob/main/docs/tutorials/understanding-gopher-plus.md Demonstrates how to configure the Mototli Gopher+ server using a TOML file. This allows customization of host, port, document root, and Gopher+ specific settings like admin information. ```toml # server.toml [server] host = "0.0.0.0" port = 7070 hostname = "my-gopherhole.example.com" document_root = "./content" [gopher_plus] enabled = true admin_name = "Your Name" admin_email = "you@example.com" ``` -------------------------------- ### Configure Fish Shell Completion for Mototli Source: https://github.com/alanbato/mototli/blob/main/docs/installation.md Enables shell completion for Mototli commands in the Fish shell. This provides interactive command-line assistance, making it easier to use Mototli's features. ```bash # Add to ~/.config/fish/config.fish mototli --show-completion fish | source ``` -------------------------------- ### Import GopherServer Components Source: https://github.com/alanbato/mototli/blob/main/docs/reference/api/index.md Import necessary components for setting up and running a Gopher server, including GopherServer, ServerConfig, and server execution functions. ```python from mototli.server import ( GopherServer, ServerConfig, run_server, start_server, ) ``` -------------------------------- ### CLI - Serve a Gopherhole Commands Source: https://context7.com/alanbato/mototli/llms.txt Illustrates command-line usage for running a Gopher server with 'mototli'. Examples include serving directories, specifying hostnames and ports, configuring admin information, using configuration files, generating configuration files, disabling directory listings or Gopher+ extensions, binding to specific interfaces, and checking the version. Requires the 'mototli' CLI tool. ```bash # Serve current directory on port 7070 mototli serve . --port 7070 # Serve specific directory with public hostname mototli serve /var/gopher --hostname gopher.example.com --port 70 # Serve with Gopher+ admin info mototli serve /var/gopher \ --admin-name "John Doe" \ --admin-email "admin@example.com" \ --port 7070 # Use configuration file mototli serve --config server.toml # Generate example configuration mototli serve --init > gopher.toml # Disable directory listings mototli serve /var/gopher --no-directory-listing --port 7070 # Disable Gopher+ extensions mototli serve /var/gopher --no-gopher-plus --port 7070 # Bind to all interfaces on default port (requires root) sudo mototli serve /var/gopher --host 0.0.0.0 # Version information mototli version ``` -------------------------------- ### Mototli CLI Error Handling: Port Permission Denied Source: https://github.com/alanbato/mototli/blob/main/docs/quickstart.md Illustrates the 'Permission denied for port 70' error, common on Unix-like systems when trying to bind to privileged ports. The solution is to use a higher, non-privileged port. ```bash # Error example: # Error: Permission denied for port 70 # Solution: mototli serve . --port 7070 ``` -------------------------------- ### Mototli CLI Error Handling: Timeout Errors Source: https://github.com/alanbato/mototli/blob/main/docs/quickstart.md Demonstrates 'Connection timed out' errors with the Mototli CLI, which can occur with slow or unreachable servers. The solution involves increasing the timeout duration using the `--timeout` flag. ```bash # Error example: # Error: Connection timed out # Solution: mototli get slow-server.example --timeout 60 ``` -------------------------------- ### Server Error Response Example (Gopher Protocol) Source: https://github.com/alanbato/mototli/blob/main/docs/explanation/architecture.md A representation of a server-generated error response in the Gopher protocol format. This specific example indicates a 'File not found' error. ```text 3Error: File not found error server.example 70 ``` -------------------------------- ### Python Gopher Client Context Manager Source: https://github.com/alanbato/mototli/blob/main/docs/explanation/architecture.md Shows how to use the GopherClient as an asynchronous context manager for simplified network operations. It handles connection setup and teardown implicitly, providing a clean API for making requests like `client.get(host, selector)`. ```python import asyncio class GopherClient: def __init__(self, timeout: float = 30.0): self.timeout = timeout # Other initialization async def __aenter__(self): # Logic to establish a connection or prepare the client print("Entering GopherClient context") # In a real implementation, this might establish a connection pool or similar return self async def __aexit__(self, exc_type, exc_val, exc_tb): # Logic to close connections or clean up resources print("Exiting GopherClient context") # In a real implementation, this would close any open connections pass async def get(self, host: str, selector: str) -> dict: # Replace dict with actual Response type # Placeholder for the actual get request logic print(f"Making GET request to {host} with selector: {selector}") # Simulate a response await asyncio.sleep(0.1) # Simulate network delay return {"status": "success", "data": f"Response for {selector}"} # Example Usage: async def main(): async with GopherClient(timeout=30.0) as client: response = await client.get("gopher.example.org", "/some/path") print(f"Received response: {response}") # asyncio.run(main()) ``` -------------------------------- ### run_server convenience function Source: https://github.com/alanbato/mototli/blob/main/docs/reference/api/server.md A convenience function to quickly start the Gopher server, serving files from a specified directory on a given port. ```APIDOC ## run_server ### Description Convenience function to start the Gopher server. ### Function `mototli.server.run_server(document_root: str, port: int)` ### Parameters - `document_root` (str): The directory to serve files from. - `port` (int): The port number to listen on. ### Usage Example ```python import asyncio from mototli.server import run_server asyncio.run(run_server(document_root=".", port=7070)) ``` ``` -------------------------------- ### GopherServer Source: https://github.com/alanbato/mototli/blob/main/docs/reference/api/server.md Represents the main Gopher server instance. It manages the server's lifecycle, including starting, stopping, and handling incoming requests based on the provided configuration. ```APIDOC ## GopherServer ### Description Manages the Gopher server instance, including configuration, starting, and stopping. ### Class `mototli.server.GopherServer` ### Methods - `__init__(self, config: ServerConfig)`: Initializes the Gopher server with the given configuration. - `start(self)`: Starts the Gopher server, making it ready to accept connections. - `stop(self)`: Stops the Gopher server gracefully. ### Usage Example ```python from mototli.server import GopherServer, ServerConfig config = ServerConfig(...) server = GopherServer(config) await server.start() # ... server runs ... await server.stop() ``` ``` -------------------------------- ### Download multiple binary files (Python) Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/handle-binary-files.md A Python script demonstrating how to download multiple binary files concurrently from a Gopher server using `mototli.client.GopherClient`. It iterates through a list of selectors and corresponding output filenames, handling potential errors during download. ```python import asyncio from pathlib import Path from mototli.client import GopherClient async def download_files(host: str, files: list[tuple[str, str]]): """Download multiple files from a gopher server. Args: host: Server hostname files: List of (selector, output_filename) tuples """ async with GopherClient() as client: for selector, output in files: try: response = await client.get_binary(host, selector) Path(output).write_bytes(response.content) print(f"Downloaded: {output} ({len(response.content)} bytes)") except Exception as e: print(f"Failed: {selector} - {e}") files = [ ("/images/logo.gif", "logo.gif"), ("/images/banner.png", "banner.png"), ("/archives/data.tar.gz", "data.tar.gz"), ] asyncio.run(download_files("localhost:7070", files)) ``` -------------------------------- ### Mototli Timeout Configuration (TOML) Source: https://github.com/alanbato/mototli/blob/main/docs/how-to/configure-server.md Sets various timeout limits for server operations, including the general request timeout and the specific timeout for CGI script execution. ```toml [limits] request_timeout = 30.0 cgi_timeout = 30.0 ```