bunkdeck!!

this blog post was written by sorrel and maren

bunkdeck is a terminal ~application suite~ that we made so it would be easier to talk to each other on our tilde server. this is her story...

IMAGINE you've found yourself in this position: you've recently started a computer club (!!!! https://startacomputer.club !!!!) with some friends. you're engaged in the project of improving the political economy of computing in the place that you live. and you want to have some fun and do some skillsharing while you do it. so you (maren) set up a tilde server and invite your friends (sorrel & [names redacted]). now that you've got some shared computing resources, what sorts of things do you get up to?

a screenshot of bunkdeck being used

one of the things we got up to was a simple chat application. we wanted something dramatically simpler than irc — you just ssh into the tilde server and write your texts to a file and read other texts from the file and everything is beautiful. so how did we do that? first was...

proclaim

proclaim is the program (part of the greater bunkdeck ~application suite~) for posting messages in the groupchat. it looks like a regular text box that you type words into and press ENTER to post them. here's the code:

#!/bin/bash -e

# make username uppercase
username=$(echo "$USER" | tr '[:lower:]' '[:upper:]')
timezone="America/New_York"
declare prompt

makeSlug () {
        # make time and date
        time=$(TZ=${timezone} date +%I:%M%p)
        date=$(TZ=${timezone} date +%m/%d)

        # make name/time string
        prompt="${username}-${date}-${time}"
}

# enter bunkchat mode (clear the screen)
clear

while true
do
        figlet -f future proclaim - bunkchat
        echo "You may view old chat with 'scry', heathen."
        echo "-------------------------------------------"
        read -r -p "speak to the server: " text
        makeSlug
        echo "${prompt}: $text" >> /srv/bunkchat.txt
        clear
done

here's the source in git

proclaim is just a bash read loop accepting input from the user. when the user presses enter, it appends what they typed to the chat file bunkchat.txt, then clears the screen and sets a clean read prompt and waits again.

for a long time, proclaim didn't have timestamps. the makeSlug() function didn't exist, and each post slug was just the username of the person who posted.

when we decided we wanted to know what time someone made a post, we implemented an unrelated cron job. this made an ASCII rooster (courtesy of cowsay) announce the time in chat every fifteen minutes. it was hilarious at first, but made reading old chat annoying because there was inevitably more rooster than chat.

heed

heed is the program (part of the greater bunkdeck ~application suite~) that displays chats to a bunkdeck user. it has a banner and looks like a textfield. when new posts are made, they automatically show up at the bottom of that textfield. here's the code:

#!/bin/sh -e

clear

figlet -f future heed - bunkchat
echo "#######################################################################"
echo "# Take heed, $USER! This is a group chat with everyone on the server! #"
echo "# You can view earlier chat with 'scry' or 'less /srv/bunkchat.txt'   #"
echo "#######################################################################"
echo

tail -f /srv/bunkchat.txt

here's the source in git

heed is even simpler than proclaim! it's literally just tailing the chat file bunkchat.txt (with just a little bit of style.) incredible!

heed is so simple it has remained unchanged since its original implementation. there was still a problem, however. running proclaim and running heed required bunkchatters to either open two ssh tunnels into our server OR have enough familiarity with terminal multiplexing to run them both in one session.

enter...

bunkdeck

bunkdeck is the ~suite~ part of the bunkdeck ~application suite~ that runs proclaim and heed in a single terminal AND gives you a shell to hack away with while you chat with your computational comrades. the code is as follows.. ..

actually, it's too long to put in this blog post, so you should just look at it here. as a teaser, here's one of her functions:

#!/bin/bash
set -e

# ...

heedPane="bunkdeck:0.0"
proclaimPane="bunkdeck:0.1"
shellPane="bunkdeck:0.2"

# ...

function startNewDeck {
	tmux new -d -s bunkdeck heed
	tmux split-window -h -t bunkdeck -p 70
	tmux split-window -t $heedPane -v -p 3
	tmux send-keys -t $proclaimPane 'proclaim' C-m
	tmux send-keys -t $shellPane 'cowsay "press [CTRL+b then o] to cycle through panes"' C-m
	# turn on pane titling
	tmux select-pane -t $heedPane -T heed
	tmux select-pane -t $proclaimPane -T proclaim
	tmux select-pane -t $shellPane -T shell
	tmux set -g set-titles on
	# attach session to shell
	tmux attach -t $shellPane
}

bunkdeck is just tmux with some little conveniences. it started its life as a couple lines to start a new tmux session, split the window into a few panes and run heed and proclaim appropriately. when bunkchatters who were new to tmux ran bunkdeck they found themselves uncertain of how to navigate around, so we enlisted a helpful cow to say “press [CTRL+b then o] to cycle through panes.” (did you know you can press [CTRL+b then o] to cycle through panes?). for a while, this caused a hilarious bug that caused all of us to post “press [CTRL+b then o] to cycle through panes.” repeatedly in the chat. so now we just yell that at each other sometimes

one of the nice things about tmux is that sessions can persist indefinitely. so, a bunkchatter could ssh into our little tilde server, start a bunkdeck session, and then leave (by choice or for wont of internet infrastructure) secure in the knowledge that they could later re-attach to the session and rejoin the chat.

sort of. it turns out tmux got weird if you try to run this original version of bunkdeck while there is already a bunkdeck session running. so! let's check for an existing bunkdeck session and attach to it if there is one. no problem! tmux lets you do that; you just need a little error-guarding:

function isExistingDeck {
        set +e
        sessions=$(tmux list-sessions)
        set -e

        if [[ $sessions == *"bunkdeck"* ]]; then
                return 0
        else
                return 1
        fi
}

this was before we split things up into functions mind you. you can see what the file looked like at this point here. after breaking up our script into functions, it was much easier to add small quality of life features, and the code is also easier to understand now

one of the quality of life features is taking the life of a bunkdeck session with the kill command which we added here. another is resizing tmux panes with user-friendly commands (grow & shrink) that abstract tmux's resize-pane flags (-D -U -L -R).

other thoughts about tilde chatting

none of us have used other tilde servers much, so we don't know how they do chat. we're really happy with what we came up with, but it has a caveat — we could only do chat this way because we all know and trust each other. without that, it wouldn't have been safe to make files world writeable and readable, and proclaim and heed rely on that. most of our little tools are built on this kind of trust <3