---------------------------------------- | |
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. | |
[0] slackz | |
If you don't know what cosmic.voyage is read this first [1] | |
[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. | |
[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.go… | |
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… | |
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/s… | |
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 " >> " … | |
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! |