Home
---------------------------------------- Cosmic Voyage - Part 1 January 20th, 2019 ---------------------------------------- slackz [0] asked me to do some write-ups on cosmic.voyage from the architect POV. Here's part 1 of who knows how many. DIR [0] slackz If you don't know what cosmic.voyage is read this first [1] DIR [1] Cosmic Voyage Being a text-based writing adventure, and me being me, I immediately set out to make Cosmic sit primarily on gopher rather than web. At first I didn't plan to have a web presence for it at all, but that changed as things went along. Really, my goals and understanding of the system are ever-evolving and greatly informed by the active users. Regardless, things started with gopher. I knew I wanted a few things right away: - A single gopher structure, not individual user folders. - Users to be able to fully control their ships and stories, but not mess with other users' things - An ongoing log that linked everything together. I use motsognir [2] on gopher.black, but I thought it might be easier to write scripts as gophermaps for cosmic if I stuck with gophernicus. I could have made things in cgi scripts, but I like the transparent heirarchical structure I get to this way instead. DIR [2] motsognir The structure of cosmic's gopher hole looks like this: ├── gophermap ├── intro.gophermap ├── listing.gophermap ├── log │ ├── gophermap │ └── intro.gophermap ├── Melchizedek (or any old ship) │ ├── 001.txt │ ├── 002.txt │ ├── 003.txt ├── Melvin P Feltersnatch (another example ship) │ ├── 001.txt │ ├── 002.txt │ └── 003.txt ├── rss.xml └── ships ├── gophermap ├── Melchizedek (example ship page directory) │ └── gophermap -> /var/gopher/ships/ship/gophermap ├── Melvin P Feltersnatch (another example ship page dir) │ └── gophermap -> /var/gopher/ships/ship/gophermap ├── ship │ └── gophermap └── ships.gophermap At the root level I have a gophermap that pulls in and processes other gophermaps, does a little shell scripting, and displays the basic content. Let's start by having a look at that code: =intro.gophermap 1Complete Transmission Log /log 1Ships, Colonies, Outposts /ships 0RSS Feed /rss.xml Most recent (20) log entries: =head -n 20 listing.gophermap | sed 's|^0||' | awk -v tot="$(wc -l listing.gophermap)" '{print 0 int(tot)-NR+1 " >> " $0}' Gophernicus allows us to source in other gophermaps by using saying =gophermapname. In this way I can keep my intro text for cosmic in a separate file (which becomes helpful later when we look at web generation). Following that I have a few regular gophermap links using gophernicus' friendly shorthand syntax (no servername or port required). Finally I list the most recent log entries. In this, I grab the top 20 lines from listing.gophermap and number them properly. listing.gophermap is the heart of the cosmic log system. Each time a user adds a log to the site, it gets prepended to that file. That file in turn generates the log page, the short listings here, and content for the individual ship pages. It's a sensitive file because it needs to be writable by all users on the system. I've kicked around better ways to do that, but for now it seems to work. At least I back it up regularly. The /log/ page works very much like the root gophermap, but with a simpler rendering. =intro.gophermap =sed 's|^0||' /var/gopher/listing.gophermap | awk -v tot="$(wc -l /var/gopher/listing.gophermap)" '{print 0 int(tot)-NR+1 " >> " $0'} Simple, right? awk is the best. So what about the ship pages? Those are a little funkier. On the one hand, they pretty much just sed/awk their way through the listing.gophermap file as well, but there's also the matter of a navigable directory. From the list above you can see that there's a ships directory. Lets look more closely at an example: └── ships ├── gophermap ├── Enterprise NCC-1701 │ └── gophermap -> /var/gopher/ships/ship/gophermap ├── ship │ └── gophermap └── ships.gophermap The root gophermap of the ships page does a little more hard work. This has a few long lines that might not render well on your screen. I apologize!: #!/bin/sh cat "ships.gophermap" find "/var/gopher/" -maxdepth 1 ! -path "/var/gopher/" ! -path "/var/gopher/ships" ! -path "/var/gopher/log" -type d -print | sed 's|/var/gopher/||' | sort | while read -r ship do entry_num=$(grep -c "^0${ship}" "/var/gopher/listing.gophermap") if [ "$entry_num" != "0" ]; then printf "1%s (%s)\\t/ships/%s\\n" "$ship" "$entry_num" "$ship" fi done We start by catting out the intro for the ships page from ships.gophermap, then we loop through all the ship directories on the system. Using each of those ships, we then check against listing.gophermap to see how many entries they have. If they don't have any entries, we leave them out of the listings. That was a nice idea from one of the cosmic users to avoid cluttering up the ship page with empty ships. If there ARE entries, we print a link to the ship page. The ship pages themselves are a bit of trickery. There's really only one ship page /ships/ship/gophermap. All the rest are just symlinks to it. But how!!?? What manner of sorcery is this? #!/bin/sh ship="$(/bin/pwd -L | sed 's|.*/||')" desc="/var/gopher/${ship}/.description" if [ -f "$desc" ]; then cat "$desc" printf "\\n" fi printf "%s - Ship Log\\n" "$ship" tac "/var/gopher/listing.gophermap" | sed "s|^0||" | awk '{print 0 NR " >> " $0}' | grep "^.*>>\\ ${ship}" pwd -L gets the path of the current symlink, which reveals the ship name! Then we look to see if there's a ship description and finally we grab all the relevant logs from listings and number everything. Huzzah! That's it. That's the whole gopher structure that drives Cosmic Voyage. Next time I'll talk about the web generation and RSS feeds. If this inspired you to join the system, instructions can be found on cosmic's home page. See you in the stars!