Building Gopher services with Python

For April Fools, 2021, I migrated Dinerville to Gopher (I know: lol). It was a refreshingly simple change from web development. Three evenings of work gave me a gopher server that presents all the content from a much more complex website.

Pituophis is a Python module for writing both Gopher servers and clients. Pituophis's default “handler” function acts as a basic Gopher server, publishing items in a specified directory to Gopherspace; an optional user-defined alternate handler function responds when a missing file is requested. You can also replace the default handler and build your own Gopher application from the ground up.

One limitation of Pituophis compared to a web framework is the lack of a routing engine. That's easy enough to work around with a list of regular expressions and “controller” functions:

if request.path in ('', '/'):
    return homePage(request)
if request.path == '/about':
    return aboutPage(request)

paths = [
    (re.compile('/image/([\w-]+)\.(gif|jpg|png)$', re.IGNORECASE), sendImage),
    (re.compile('/([a-z]{2})$'), statePage),
    (re.compile('/([a-z]{2})/([\w-]+)$'), cityPage),

for pat, func in paths:
    m = pat.match(request.path)
    if m:
        return func(request, m)

Gopher Responses

While it’s possible to just serve text files from Gopher, at some point you’ll need to construct a menu (Wikipedia was surprisingly helpful with the syntax here). The term “menu” covers any gopher interface that includes links. Menus are tab-separated value files—the first column is a one-character content-type code followed by text that’s displayed to the user; that’s followed by an address on the server you’re linking to, the server address itself, and a port number. These columns are all required even for informational lines.

The lines below that start with “1” are links to other menus; lines with “i” (lowercase i) are “informational”, meaning just lines of text. Other important codes are “h” for HTML pages and “I” (uppercase I) for images.

i	/		0
1Gopherpedia	/	70
1Floodgap systems, including the Veronica-2 search engine	/	70
1The Gopher Movie Database	/1/cgi-bin/	70 (A collection of Gopher logs, or "phlogs")	/1/phlogs/	70

Building Menus with Pituophis

Pituophis provides an Item class that represents an individual line of a gopher menu and will convert a list of them, returned from a handler function, into a Gopher menu page. This code comes after a few database queries and returns basic information about a diner, including links to photos and outside info:

outp =  [Item(text=f'{} ({diner.make}{serial})'),
          Item(text=f"{}, {diner.state}  {}"),
          Item(text=f"Status: {diner.status_str}"),]
outp += [Item(itype='h', text=row.title, path=f"URL:{row.url}") for row in links]
outp += [Item(itype='I', text=caption[0], path=f"/image/{photo.filename}", host=settings.HOST, port=settings.PORT)]

(Item(), in the code above, produces a blank line).


That's a very basic overview, but hopefully enough for some exploration if you're interested.

#gopher #python #django