From 8b5efd58f03eaf9502b96bb8f38a5ffb428c9cf5 Mon Sep 17 00:00:00 2001 From: "Michael F. Lamb" Date: Thu, 15 Oct 2015 02:56:11 -0400 Subject: [PATCH 01/14] add tdp-format stats script --- scripts/tdp.py | 204 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100755 scripts/tdp.py diff --git a/scripts/tdp.py b/scripts/tdp.py new file mode 100755 index 0000000..b3b3d18 --- /dev/null +++ b/scripts/tdp.py @@ -0,0 +1,204 @@ +#!/usr/local/bin/python3 + +# tdp.py - tilde data in tilde data protocol format. +# Copyright 2015 Michael F. Lamb +# License: GPLv3+ + +""" +Outputs JSON data conforming to "~dp (Tilde Description Protocol)" as defined +at: http://protocol.club/~datagrok/beta-wiki/tdp.html + +It is a JSON structure of the form: + +{ + 'name': (string) the name of the server. + 'url': (string) the URL of the server. + 'signup_url': (string) the URL of a page describing the process required to request an account on the server. + 'user_count': (number) the number of users currently registered on the server. + 'want_users': (boolean) whether the server is currently accepting new user requests. + 'admin_email': (string) the email address of the primary server administrator. + 'description': (string) a free-form description for the server. + 'users': [ (array) an array of users on the server. + { + 'username': (string) the username of the user. + 'title': (string) the HTML title of the user’s index.html page. + 'mtime': (number) a timestamp representing the last time the user’s index.html was modified. + }, + ... + ] + } + +We also overload this with the preexisting data format we were using in +/var/local/tildetown/tildetown-py/stats.py, which is of the form: + +{ + 'all_users': [ (array) of users on the server. + { + 'username': (string) the username of the user. + 'default': (boolean) Is the user still using their unmodified default index.html? + 'favicon': (string) a url to an image representing the user + }, + ... + ] + 'num_users': (number) count of all_users + 'live_users': [ (array) an array of live users, same format as all_users. Users may appear in both arrays. + ... + ], + 'num_live_users': (number) count of live users + 'active_user_count': (number) count of currently logged in users + 'generated_at': (string) the time this JSON was generated in '%Y-%m-%d %H:%M:%S' format. + 'generated_at_msec': (number) the time this JSON was generated, in milliseconds since the epoch. + 'site_name': (same as 'name' above) + 'site_url': (same as 'url' above) + 'uptime': (string) output of `uptime -p` + +} +Usage: tdp.py > /var/www/html/tilde.json +""" + +# I suppose I could import /var/local/tildetown/tildetown-py/stats.py which +# does much of the same work, but I wanted to try to make one that needs no +# venv nor 'sh' module. (Success.) Bonus: this runs in 0.127s, vs 5.2s +# for 'stats' + +# FIXME: unlike stats.py, we calculate last modified only on index.html. + +# FIXME: we output quite a bit of redundant data. I think we should lose +# 'live_users' and do that filtering on the client side. + +# FIXME: If we're the only consumer of the stats.py data, let's change the +# client side to use 'users' and drop 'all_users'. + +import datetime +import hashlib +import json +import os +import pwd +import re +import struct +import subprocess + +title_re = re.compile(r']*>(.*)', re.DOTALL) +defaultindex_hash = None + +# modified from https://gist.github.com/likexian/f9da722585036d372dca +XTMP_STRUCT_FMT = 'hi32s4s32s256shhiii4i20x' +XTMP_STRUCT_SIZE = struct.calcsize(XTMP_STRUCT_FMT) +XTMP_STRUCT_KEYS = [ + 'type', 'pid', 'line', 'id', 'user', 'host', 'e_termination', 'e_exit', + 'session', 'sec', 'usec', 'addr_v6', 'unused', + ] + +def read_xtmp(filename): + """Pure-python replacement for who(1) and w(1); parses the data structure + in /var/run/utmp or /var/run/wtmp, generating a dict for each entry. See + man 5 utmp for meaning of fields. + + """ + # This was fun but probably not worth the trouble, since we end up having + # to use subprocess.check_output() elsewhere anyway. + with open(filename, 'rb') as fp: + for entry in iter((lambda: fp.read(XTMP_STRUCT_SIZE)), b''): + yield dict(zip( + XTMP_STRUCT_KEYS, + (i.decode('UTF-8').partition('\x00')[0] if hasattr(i, 'partition') else i + for i in struct.unpack(XTMP_STRUCT_FMT, entry)))) + +def active_user_count(): + """Return the count of unique usernames logged in.""" + return len(set(r['user'] for r in read_xtmp('/var/run/utmp') if r['type'] == 7)) + +def md5sum(filename): + """Return the md5 hash of the contents of filename as a hexidecimal string.""" + # This doesn't slurp the whole file in; it reads 4k at a time. + h = hashlib.md5() + with open(filename, 'rb') as fp: + for data in iter((lambda: fp.read(4096)), b''): + h.update(data) + return h.hexdigest() + +def get_title(indexhtml): + """Given an html file, return the content of its """ + print(indexhtml) + fp = open(indexhtml, 'rt', errors='ignore') + title = title_re.search(fp.read()) + if title: + return title.group(1) + +def get_users(): + """Generate tuples of the form (username, homedir) for all normal + users on this system. + + """ + return ((p.pw_name, p.pw_dir) for p in pwd.getpwall() if + p.pw_uid >= 1000 and + p.pw_shell != '/bin/false' and + p.pw_name not in ['nobody', 'ubuntu', 'poetry']) + +def tdp_user(username, homedir): + """Given a unix username, and their home directory, return a TDP format + dict with information about that user. + + """ + indexhtml = os.path.join(homedir, 'public_html', 'index.html') + return { + 'username': username, + 'title': get_title(indexhtml), + 'mtime': int(os.path.getmtime(indexhtml) * 1000), + # tilde.town extensions and backward compatibility + # FIXME: just shelling out to diff -q might be way faster than all + # these hashes. + 'default': md5sum(indexhtml) == defaultindex_hash, + 'favicon': 'TODO', + } + +def tdp(): + now = datetime.datetime.now() + users = [tdp_user(username, homedir) for username, homedir in get_users()] + + # TDP format data + data = { + 'name': 'tilde.town', + 'url': 'http://tilde.town', + 'signup_url': 'http://goo.gl/forms/8IvQFTDjlo', + 'want_users': True, + 'admin_email': 'nks@lambdaphil.es', + 'description': " ".join(l.strip() for l in """ + an intentional digital community for creating and sharing works of + art, educating peers, and technological anachronism. we are a + completely non-commercial, donation supported, and committed to + rejecting false technological progress in favor of empathy and + sustainable computing. + """.splitlines()), + 'user_count': len(users), + 'users': users, + } + + # tilde.town extensions and backward compatibility + data.update({ + 'active_user_count': active_user_count(), + 'generated_at': now.strftime('%Y-%m-%d %H:%M:%S'), + 'generated_at_msec': int(now.timestamp() * 1000), + 'uptime': subprocess.check_output(['uptime', '-p'], universal_newlines=True), + }) + # redundant entries we should drop after changing homepage template + data.update({ + 'all_users': data['users'], + 'num_users': data['user_count'], + 'live_users': [u for u in data['users'] if not u['default']], + 'site_name': data['name'], + 'site_url': data['url'], + }) + data.update({ + 'num_live_users': len(data['live_users']), + }) + + return data + +def main(): + global defaultindex_hash + defaultindex_hash = md5sum("/etc/skel/public_html/index.html") + print(json.dumps(tdp(), sort_keys=True, indent=2)) + +if __name__ == '__main__': + raise SystemExit(main()) From 470bef5f05826e4c005994e586b8989ece490b0b Mon Sep 17 00:00:00 2001 From: "Michael F. Lamb" <mike@datagrok.org> Date: Tue, 20 Oct 2015 02:37:37 -0400 Subject: [PATCH 02/14] +replace manual diff with call out to diff(1) --- tildetown/stats.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tildetown/stats.py b/tildetown/stats.py index 7176f8f..d8a8ec6 100644 --- a/tildetown/stats.py +++ b/tildetown/stats.py @@ -5,6 +5,7 @@ from os.path import getmtime, join from datetime import datetime from sh import find, uptime, who, sort, wc, cut from tildetown.util import slurp, thread, p +import subprocess # this script emits json on standard out that has information about tilde.town # users. It denotes who has not updated their page from the default. It also @@ -12,12 +13,14 @@ from tildetown.util import slurp, thread, p SYSTEM_USERS = ['wiki', 'root', 'ubuntu', 'nate'] -DEFAULT_HTML = slurp("/etc/skel/public_html/index.html") +DEFAULT_HTML_FILENAME = "/etc/skel/public_html/index.html" username_to_html_path = lambda u: "/home/{}/public_html".format(u) def default_p(username): - return DEFAULT_HTML == slurp(join(username_to_html_path(username), "index.html")) + return subprocess.call( + ['diff', '-q', DEFAULT_HTML_FILENAME, user_html_filename], + stdout=subprocess.DEVNULL) == 0 def bounded_find(path): # find might return 1 but still have worked fine. From 65e1ec1a5d951df07d18a0c3b3563c4fcd01d628 Mon Sep 17 00:00:00 2001 From: "Michael F. Lamb" <mike@datagrok.org> Date: Tue, 20 Oct 2015 15:50:23 -0400 Subject: [PATCH 03/14] tdp.py->stats.py --- scripts/tdp.py | 204 ------------------------------------- tildetown/stats.py | 247 ++++++++++++++++++++++++++++++++------------- 2 files changed, 179 insertions(+), 272 deletions(-) delete mode 100755 scripts/tdp.py mode change 100644 => 100755 tildetown/stats.py diff --git a/scripts/tdp.py b/scripts/tdp.py deleted file mode 100755 index b3b3d18..0000000 --- a/scripts/tdp.py +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/local/bin/python3 - -# tdp.py - tilde data in tilde data protocol format. -# Copyright 2015 Michael F. Lamb <http://datagrok.org> -# License: GPLv3+ - -""" -Outputs JSON data conforming to "~dp (Tilde Description Protocol)" as defined -at: http://protocol.club/~datagrok/beta-wiki/tdp.html - -It is a JSON structure of the form: - -{ - 'name': (string) the name of the server. - 'url': (string) the URL of the server. - 'signup_url': (string) the URL of a page describing the process required to request an account on the server. - 'user_count': (number) the number of users currently registered on the server. - 'want_users': (boolean) whether the server is currently accepting new user requests. - 'admin_email': (string) the email address of the primary server administrator. - 'description': (string) a free-form description for the server. - 'users': [ (array) an array of users on the server. - { - 'username': (string) the username of the user. - 'title': (string) the HTML title of the user’s index.html page. - 'mtime': (number) a timestamp representing the last time the user’s index.html was modified. - }, - ... - ] - } - -We also overload this with the preexisting data format we were using in -/var/local/tildetown/tildetown-py/stats.py, which is of the form: - -{ - 'all_users': [ (array) of users on the server. - { - 'username': (string) the username of the user. - 'default': (boolean) Is the user still using their unmodified default index.html? - 'favicon': (string) a url to an image representing the user - }, - ... - ] - 'num_users': (number) count of all_users - 'live_users': [ (array) an array of live users, same format as all_users. Users may appear in both arrays. - ... - ], - 'num_live_users': (number) count of live users - 'active_user_count': (number) count of currently logged in users - 'generated_at': (string) the time this JSON was generated in '%Y-%m-%d %H:%M:%S' format. - 'generated_at_msec': (number) the time this JSON was generated, in milliseconds since the epoch. - 'site_name': (same as 'name' above) - 'site_url': (same as 'url' above) - 'uptime': (string) output of `uptime -p` - -} -Usage: tdp.py > /var/www/html/tilde.json -""" - -# I suppose I could import /var/local/tildetown/tildetown-py/stats.py which -# does much of the same work, but I wanted to try to make one that needs no -# venv nor 'sh' module. (Success.) Bonus: this runs in 0.127s, vs 5.2s -# for 'stats' - -# FIXME: unlike stats.py, we calculate last modified only on index.html. - -# FIXME: we output quite a bit of redundant data. I think we should lose -# 'live_users' and do that filtering on the client side. - -# FIXME: If we're the only consumer of the stats.py data, let's change the -# client side to use 'users' and drop 'all_users'. - -import datetime -import hashlib -import json -import os -import pwd -import re -import struct -import subprocess - -title_re = re.compile(r'<title[^>]*>(.*)', re.DOTALL) -defaultindex_hash = None - -# modified from https://gist.github.com/likexian/f9da722585036d372dca -XTMP_STRUCT_FMT = 'hi32s4s32s256shhiii4i20x' -XTMP_STRUCT_SIZE = struct.calcsize(XTMP_STRUCT_FMT) -XTMP_STRUCT_KEYS = [ - 'type', 'pid', 'line', 'id', 'user', 'host', 'e_termination', 'e_exit', - 'session', 'sec', 'usec', 'addr_v6', 'unused', - ] - -def read_xtmp(filename): - """Pure-python replacement for who(1) and w(1); parses the data structure - in /var/run/utmp or /var/run/wtmp, generating a dict for each entry. See - man 5 utmp for meaning of fields. - - """ - # This was fun but probably not worth the trouble, since we end up having - # to use subprocess.check_output() elsewhere anyway. - with open(filename, 'rb') as fp: - for entry in iter((lambda: fp.read(XTMP_STRUCT_SIZE)), b''): - yield dict(zip( - XTMP_STRUCT_KEYS, - (i.decode('UTF-8').partition('\x00')[0] if hasattr(i, 'partition') else i - for i in struct.unpack(XTMP_STRUCT_FMT, entry)))) - -def active_user_count(): - """Return the count of unique usernames logged in.""" - return len(set(r['user'] for r in read_xtmp('/var/run/utmp') if r['type'] == 7)) - -def md5sum(filename): - """Return the md5 hash of the contents of filename as a hexidecimal string.""" - # This doesn't slurp the whole file in; it reads 4k at a time. - h = hashlib.md5() - with open(filename, 'rb') as fp: - for data in iter((lambda: fp.read(4096)), b''): - h.update(data) - return h.hexdigest() - -def get_title(indexhtml): - """Given an html file, return the content of its """ - print(indexhtml) - fp = open(indexhtml, 'rt', errors='ignore') - title = title_re.search(fp.read()) - if title: - return title.group(1) - -def get_users(): - """Generate tuples of the form (username, homedir) for all normal - users on this system. - - """ - return ((p.pw_name, p.pw_dir) for p in pwd.getpwall() if - p.pw_uid >= 1000 and - p.pw_shell != '/bin/false' and - p.pw_name not in ['nobody', 'ubuntu', 'poetry']) - -def tdp_user(username, homedir): - """Given a unix username, and their home directory, return a TDP format - dict with information about that user. - - """ - indexhtml = os.path.join(homedir, 'public_html', 'index.html') - return { - 'username': username, - 'title': get_title(indexhtml), - 'mtime': int(os.path.getmtime(indexhtml) * 1000), - # tilde.town extensions and backward compatibility - # FIXME: just shelling out to diff -q might be way faster than all - # these hashes. - 'default': md5sum(indexhtml) == defaultindex_hash, - 'favicon': 'TODO', - } - -def tdp(): - now = datetime.datetime.now() - users = [tdp_user(username, homedir) for username, homedir in get_users()] - - # TDP format data - data = { - 'name': 'tilde.town', - 'url': 'http://tilde.town', - 'signup_url': 'http://goo.gl/forms/8IvQFTDjlo', - 'want_users': True, - 'admin_email': 'nks@lambdaphil.es', - 'description': " ".join(l.strip() for l in """ - an intentional digital community for creating and sharing works of - art, educating peers, and technological anachronism. we are a - completely non-commercial, donation supported, and committed to - rejecting false technological progress in favor of empathy and - sustainable computing. - """.splitlines()), - 'user_count': len(users), - 'users': users, - } - - # tilde.town extensions and backward compatibility - data.update({ - 'active_user_count': active_user_count(), - 'generated_at': now.strftime('%Y-%m-%d %H:%M:%S'), - 'generated_at_msec': int(now.timestamp() * 1000), - 'uptime': subprocess.check_output(['uptime', '-p'], universal_newlines=True), - }) - # redundant entries we should drop after changing homepage template - data.update({ - 'all_users': data['users'], - 'num_users': data['user_count'], - 'live_users': [u for u in data['users'] if not u['default']], - 'site_name': data['name'], - 'site_url': data['url'], - }) - data.update({ - 'num_live_users': len(data['live_users']), - }) - - return data - -def main(): - global defaultindex_hash - defaultindex_hash = md5sum("/etc/skel/public_html/index.html") - print(json.dumps(tdp(), sort_keys=True, indent=2)) - -if __name__ == '__main__': - raise SystemExit(main()) diff --git a/tildetown/stats.py b/tildetown/stats.py old mode 100644 new mode 100755 index d8a8ec6..766e2f9 --- a/tildetown/stats.py +++ b/tildetown/stats.py @@ -1,87 +1,198 @@ +#!/usr/local/bin/python3 + +# tdp.py - tilde data in tilde data protocol format. +# Copyright 2015 Michael F. Lamb <http://datagrok.org> +# License: GPLv3+ + +""" +Outputs JSON data conforming to "~dp (Tilde Description Protocol)" as defined +at: http://protocol.club/~datagrok/beta-wiki/tdp.html + +It is a JSON structure of the form: + +{ + 'name': (string) the name of the server. + 'url': (string) the URL of the server. + 'signup_url': (string) the URL of a page describing the process required to request an account on the server. + 'user_count': (number) the number of users currently registered on the server. + 'want_users': (boolean) whether the server is currently accepting new user requests. + 'admin_email': (string) the email address of the primary server administrator. + 'description': (string) a free-form description for the server. + 'users': [ (array) an array of users on the server. + { + 'username': (string) the username of the user. + 'title': (string) the HTML title of the user’s index.html page. + 'mtime': (number) a timestamp representing the last time the user’s index.html was modified. + }, + ... + ] + } + +We also overload this with the preexisting data format we were using in +/var/local/tildetown/tildetown-py/stats.py, which is of the form: + +{ + 'all_users': [ (array) of users on the server. + { + 'username': (string) the username of the user. + 'default': (boolean) Is the user still using their unmodified default index.html? + 'favicon': (string) a url to an image representing the user + }, + ... + ] + 'num_users': (number) count of all_users + 'live_users': [ (array) an array of live users, same format as all_users. Users may appear in both arrays. + ... + ], + 'num_live_users': (number) count of live users + 'active_user_count': (number) count of currently logged in users + 'generated_at': (string) the time this JSON was generated in '%Y-%m-%d %H:%M:%S' format. + 'generated_at_msec': (number) the time this JSON was generated, in milliseconds since the epoch. + 'site_name': (same as 'name' above) + 'site_url': (same as 'url' above) + 'uptime': (string) output of `uptime -p` + +} +Usage: tdp.py > /var/www/html/tilde.json +""" + +# I suppose I could import /var/local/tildetown/tildetown-py/stats.py which +# does much of the same work, but I wanted to try to make one that needs no +# venv nor 'sh' module. (Success.) Bonus: this runs in 0.127s, vs 5.2s +# for 'stats' + +# FIXME: we output quite a bit of redundant data. I think we should lose +# 'live_users' and do that filtering on the client side. + +# FIXME: If we're the only consumer of the stats.py data, let's change the +# client side to use 'users' and drop 'all_users'. + +import datetime +import hashlib import json -from functools import partial -from os import listdir -from os.path import getmtime, join -from datetime import datetime -from sh import find, uptime, who, sort, wc, cut -from tildetown.util import slurp, thread, p +import os +import pwd +import re +import struct import subprocess -# this script emits json on standard out that has information about tilde.town -# users. It denotes who has not updated their page from the default. It also -# reports the time this script was run. The user list is sorted by public_html update time. - -SYSTEM_USERS = ['wiki', 'root', 'ubuntu', 'nate'] - +SYSTEM_USERS = ['wiki', 'root', 'ubuntu', 'nate', 'nobody'] DEFAULT_HTML_FILENAME = "/etc/skel/public_html/index.html" +title_re = re.compile(r'<title[^>]*>(.*)', re.DOTALL) -username_to_html_path = lambda u: "/home/{}/public_html".format(u) +def active_user_count(): + """Return the count of unique usernames logged in.""" + return len(set(line.split()[0] for line in + subprocess.check_output( + ["who"], universal_newlines=True).splitlines())) -def default_p(username): - return subprocess.call( - ['diff', '-q', DEFAULT_HTML_FILENAME, user_html_filename], - stdout=subprocess.DEVNULL) == 0 +def get_title(indexhtml): + """Given an html file, return the content of its """ + with open(indexhtml, 'rt', errors='ignore') as fp: + title = title_re.search(fp.read()) + if title: + return title.group(1) -def bounded_find(path): - # find might return 1 but still have worked fine. - return find(path, "-maxdepth", "3", _ok_code=[0,1]) +def get_users(): + """Generate tuples of the form (username, homedir) for all normal + users on this system. -def get_active_user_count(): - return int(wc(sort(cut(who(), "-d", " ", "-f1"), "-u"), "-l")) + """ + return ((p.pw_name, p.pw_dir) for p in pwd.getpwall() if + p.pw_uid >= 1000 and + p.pw_shell != '/bin/false' and + p.pw_name not in SYSTEM_USERS) -def guarded_mtime(path): - try: - return getmtime(path.rstrip()) - except Exception as _: - return 0 +def most_recent_within(path): + """Return the most recent timestamp among all files within path, 3 + levels deep. + """ + return max(modified_times(path), maxdepth=3) -def modify_time(username): - files_to_mtimes = partial(map, guarded_mtime) - return thread(username, - username_to_html_path, - bounded_find, - files_to_mtimes, - list, - max) +def modified_times(path, maxdepth=None): + """Walk the directories in path, generating timestamps for all + files. + """ + for root, dirs, files in os.walk(path): + if maxdepth and len(root[len(path):].split(os.sep)) == maxdepth: + dirs.clear() + for f in files: + try: + yield os.path.getmtime(os.path.join(root, f)) + except FileNotFoundError: + pass -def sort_user_list(usernames): - return sorted(usernames, key=modify_time) +def tdp_user(username, homedir): + """Given a unix username, and their home directory, return a TDP format + dict with information about that user. -def user_generator(): - ignore_system_users = lambda un: un not in SYSTEM_USERS - return filter(ignore_system_users, listdir("/home")) + """ + public_html = os.path.join(homedir, 'public_html') + index_html = os.path.join(public_html, 'index.html') + if os.path.exists(index_html): + return { + 'username': username, + 'title': get_title(index_html), + 'mtime': int(most_recent_within(public_html) * 1000), + # tilde.town extensions and backward compatibility + # FIXME: just shelling out to diff -q might be way faster than all + # these hashes. + 'favicon': 'TODO', + 'default': subprocess.call( + ['diff', '-q', DEFAULT_HTML_FILENAME, index_html], + stdout=subprocess.DEVNULL) == 0, + } + else: + return { + 'username': username, + 'default': False + } -def get_user_data(): - username_to_data = lambda u: {'username': u, - 'default': default_p(u), - 'favicon':'TODO'} - live_p = lambda user: not user['default'] +def tdp(): + now = datetime.datetime.now() + users = [tdp_user(u, h) for u, h in get_users()] - all_users = thread(user_generator(), - sort_user_list, - reversed, - partial(map, username_to_data), - list) + # TDP format data + data = { + 'name': 'tilde.town', + 'url': 'http://tilde.town', + 'signup_url': 'http://goo.gl/forms/8IvQFTDjlo', + 'want_users': True, + 'admin_email': 'nks@lambdaphil.es', + 'description': " ".join(l.strip() for l in """ + an intentional digital community for creating and sharing works of + art, educating peers, and technological anachronism. we are a + completely non-commercial, donation supported, and committed to + rejecting false technological progress in favor of empathy and + sustainable computing. + """.splitlines()), + 'user_count': len(users), + 'users': users, + } - live_users = list(filter(live_p, all_users)) + # tilde.town extensions and backward compatibility + data.update({ + 'active_user_count': active_user_count(), + 'generated_at': now.strftime('%Y-%m-%d %H:%M:%S'), + 'generated_at_msec': int(now.timestamp() * 1000), + 'uptime': subprocess.check_output(['uptime', '-p'], universal_newlines=True), + }) + # redundant entries we should drop after changing homepage template + data.update({ + 'all_users': data['users'], + 'num_users': data['user_count'], + 'live_users': [u for u in data['users'] if not u['default']], + 'site_name': data['name'], + 'site_url': data['url'], + }) + data.update({ + 'num_live_users': len(data['live_users']), + }) - active_user_count = get_active_user_count() - - return {'all_users': all_users, - 'num_users': len(all_users), - 'num_live_users': len(live_users), - 'active_user_count': active_user_count, - 'live_users': live_users,} - -def get_data(): - user_data = get_user_data() - data = {'generated_at': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), - 'site_name': 'tilde.town', - 'site_url': 'http://tilde.town', - 'uptime': str(uptime('-p')).rstrip(),} - - data.update(user_data) return data +def main(): + print(json.dumps(tdp(), sort_keys=True, indent=2)) + if __name__ == '__main__': - print(json.dumps(get_data())) + raise SystemExit(main()) From a1fec5013cee742714fac209cab434c3f3d38805 Mon Sep 17 00:00:00 2001 From: "Michael F. Lamb" <mike@datagrok.org> Date: Tue, 20 Oct 2015 20:46:59 +0000 Subject: [PATCH 04/14] fix typos --- tildetown/stats.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tildetown/stats.py b/tildetown/stats.py index 766e2f9..aee020b 100755 --- a/tildetown/stats.py +++ b/tildetown/stats.py @@ -107,7 +107,7 @@ def most_recent_within(path): """Return the most recent timestamp among all files within path, 3 levels deep. """ - return max(modified_times(path), maxdepth=3) + return max(modified_times(path, maxdepth=3)) def modified_times(path, maxdepth=None): """Walk the directories in path, generating timestamps for all @@ -119,7 +119,7 @@ def modified_times(path, maxdepth=None): for f in files: try: yield os.path.getmtime(os.path.join(root, f)) - except FileNotFoundError: + except (FileNotFoundError, PermissionError): pass def tdp_user(username, homedir): From 5d9971110352ab7d75d8b16fd14808016ab7ddbd Mon Sep 17 00:00:00 2001 From: "Michael F. Lamb" <mike@datagrok.org> Date: Tue, 20 Oct 2015 20:48:04 +0000 Subject: [PATCH 05/14] commit /var/www/tilde.town/old.template.index.html --- tildetown/templates/frontpage.html | 282 +++++++++++++++++++++++++++++ 1 file changed, 282 insertions(+) create mode 100644 tildetown/templates/frontpage.html diff --git a/tildetown/templates/frontpage.html b/tildetown/templates/frontpage.html new file mode 100644 index 0000000..ea52f4b --- /dev/null +++ b/tildetown/templates/frontpage.html @@ -0,0 +1,282 @@ +<html> + <head> + <title>welcome to tilde town! + + + + +

tilde.town is a small unix server built for sharing

+~*~*~* {{active_user_count}} townies active right now *~*~*~ +donate to tilde.town + + + + + + +
+

users

+our esteemed users ({{num_users}})
+generated at {{generated_at}}
+ +
    + {{#users}} +
  • + {{username}} + {{#default}}(default :3){{/default}} +
  • + {{/users}} +
+
+

what is the tilde.town?

+

tilde.town is an intentional community focused on radical inclusivity and the creation of digital art. We strive to create a place that is open to people of all backgrounds and technical ability and strive together to make beautiful works of art that can be conveyed via the web.

+

how do i join tilde.town?

+

sign up with this fancy form, here! it takes a few days since there is +just one person managing the signups and each user must be manually added. +Please read our code of +conduct and only sign up if you agree to be bound by it.

+

sign up form

+

what isn't tilde.town?

+

it's never super fun to define stuff in a negative sense, but there has been a lot of confusion around what tilde.town is and isn't. tilde.town is not a startup. it is not commercial in any way. tilde.town, as a side effect, has features of a social network but it is not intended to be the "next" anything (except maybe geocities or angelfire). tilde.town is not tilde.club but is inspired by it.

+

who is tilde.town?

+

tilde.town is made up of its members. we are a group of creative folk +interested in peer education and digital art. the founder is ~vilmibm whom you are more than welcome to +talk at via twitter or email.

+

why tilde.town?

+

making websites is harder than ever; everything that +can be commercialized is being commercialized; knowledge is being carved up and +locked away for profit; software is increasingly proprietary and bloated. +tilde.town is an experiment in reclaiming a bygone era of low-barrier, +judgement-free, low stakes expression with a focus on low-tech art and +pseudonymous creation.

+
+

tilde town news

+ +

donations! also, new disk

+

Wed Apr 29 06:04:58 UTC 2015

An exciting day for +tilde.town. We now have way to donate via patreon. Thanks to all the +folx who have already become patrons! y'all make the heart of this sysadmin +warm and fuzz. A big part of the push for donations was a need for more server +space which we have as of tonight's server upgrade/reboot. The main tilde.town +server now has a 40gb disk. Enjoy!

+ +

Some updates coming down the pipe: +

    +
  • 2gb quota for all users
  • +
  • fixed poetry server
  • +
  • better signup process/docs
  • +
+

+ +

welcome haiku

+

Thu Mar 5 21:19:42 UTC 2015

+

If you signed up in the last two months or so you had a bum welcome present +in your /home. the script has been fixed and now everyone retroactively has a +welcome haiku in their home directory. enjoy.

+ +

server restart

+

Tue Jan 27 21:13:27 UTC 2015

+

Hi. Today tilde.town had to restart to pick up a patch for CVE 2015-0235. +data.tilde.town (our poetry server) has also been patched and restated. Sorry +for any inconvenience!

+ +

lots of people

+

Thu Jan 1 07:37:16 UTC 2015

+

we have ~370 users. isn't that wild?

+ +

Scheduled Downtime Tonight

+

Wed Nov 26 21:19:12 UTC 2014

+ +

To accommodate our growing user base, there will be a server resize/reboot +tonight (Pacific time). Sadly I cannot give an exact time as I still don't have +internet at my new place and will have to opportunistically find some to +execute this upgrade.

+

The server should only be down for a few minutes, but this will terminate +any running applications (like tmux/screen/irssi). Any files open in an editor +should be preserved by a swap file but you still may want to save and close +things in the next several hours.

+

Also, this upgrade means that tilde.town is no longer an essentially free +project, so I may put up something for donations soon.

+ +

100+ users party report

+

Sun Nov 9 23:07:08 UTC 2014 +

tilde.town now has 102 users. We crossed into three digits last night and +lots of townies hung out in irc to celebrate. Some new features even +launched!

+ +
    +
  • the homepage userlist is now sorted by modified time
  • +
  • there is now a shared
    tweet
    command that all users can use to tweet to the @tildetown account (protip:
    haiku | tweet
    )
  • +
  • run
    random_pokemon.sh
    to get a random ascii art pokemon (thanks, ~sanqui)
  • +
  • an insane git-based wiki that all townies can edit (thanks for the help, ~datagrok)
  • +
  • an IRC bot (thanks, ~selfsame) that plays numberwang
  • +
  • even moar learnings up on the page of ~shanx
  • +
  • general good feels
  • +
+ +

80 users!

+

Wed Oct 29 18:19:45 UTC 2014 + +

tilde.town just added its 80th user. Welcome! Some folks have been having +trouble with ssh public keys. Remember, public keys are really confusing if you +aren't too familiar with them, and there is no judgement if you can't +immediately get them to work. Feel free to tweet at @tildetown or send an email to ~vilmibm if you'd like some help.

+ +

+ +

60 users

+

Sat Oct 25 19:37:47 UTC 2014 +

tilde.town is up to 60 users. This is lovely! It is also only a tenth of our +planned total user capacity, so if you are interested in a tilde* account we'd +love to have you. You can even submit a user request with a fancy form now!

+ +

+submit a user account request! +

+

+ +

Change of IP, warnings when you ssh

+

Sun Oct 19 03:28:59 UTC 2014

+

+ In the interest of making sure we don't suddenly disappear from the Internet +as a result of a dynamic IP change on AWS I switched to using an Elastic +IP (amusingly, "elastic" IPs are static). +

+ +

+The upside is that we now have a static IP (also it's free) (woo). +

+ +

+The downside is that when you try to SSH into tilde.town, now, you'll get an +error about "something nasty" and there will be many @ characters. You'll want +to edit your .ssh/known_hosts file and remove the entry for tilde.town (your +error message should have a cute copy-pasta-able one-liner for doing this for +you). +

+ +

+Go ahead and do that, and then log in With Confidence. Hopefully this won't happen again. +

+ +

+I'll close by mentioning the imminent arrival of many new tildeverse members. We (the tildeverse operators) are just about ready to accept the signups currently languishing in a waitlist. This means lots of new users, which is lovely, but may mean some growing pains while I adapt our server to the new user load in the most cost-effective way. +

+ +
+ + + + + + +
+
+ Have you guess 'd you yourself would not continue?
+ The wanderer would not heed me
+`` He told me at parting, that he should soon write
+ Mr. Elton looked all happiness at this proposition
+ what is it to us what the rest do or think?
+ I doubted it more the next day on Box Hill
+
+ Come thou, arise from the ground unto the place yonder
+ One was the son of Mars, and was killed before Troy
+ He had done his duty and could return to his son.
+ I never saw any thing so outree!
+; woods, together with mountains, are on fire.
+`` He told me at parting, that he should soon write
+
+`` He told me at parting, that he should soon write
+; and, abhorring the light, they fly { abroad} by night.
+ Can not you guess what this parcel holds?''
+ And these things I see suddenly, what mean they?
+ And you, paid to defile the People
+ Very strongly may be sincerely fainting.
+
+ she cried with a most open eagerness
+`` He told me at parting, that he should soon write
+ Let me hear from you without delay
+ By him she was put in mind of what she might do
+; but Emma 's countenance was as steady as her words.
+ Dear Miss Woodhouse, do advise me.''
+
+ It was certainly ‘barbara’ in the eyes of a Greek
+ One can not creep upon a journey
+ One was the son of Mars, and was killed before Troy
+`` He told me at parting, that he should soon write
+[ 77 and struck the guilty{ draught} from his mouth.
+; The golden sun of June declines, It has not caught her eye.
+
+ Clarke translates ‘miseri senis ore,
+: naught there is Save body, having property of touch.
+ Alas poor boy, he will never be better,
+; but if he wished to do it, it might be done.
+`` He told me at parting, that he should soon write
+ One was the son of Mars, and was killed before Troy
+
+ I knew who it came from. The virgin shrieks aloud
+ To feel the presence of a brave commanding officer But she was always right.
+ I 'd rather you would.'' This was a river of Troy
+
+
+
+orators, singers, musicians to come!
+ She will break it to you better than I can.
+ Saturn expelled his father, and seized his throne
+-- I wish our opinions were the same.
+ Ere departing fade from my eyes your forests of bayonets
+ Emma soon recollected, and understood him
+
+--'''' My dear papa, he is three-and-twenty.
+ I hope time has not made you less willing to pardon.
+; Nay-be calm, for I am so: Does it burn?
+ She will break it to you better than I can.
+ play the part that looks back on the actor or actress!
+ She continued to look back, but in vain
+
+ It is necessary and beside the large sort is puff.
+; she is living in dread of the visit.
+ Year of comets and meteors transient and strange
+;'' remember that I am here.-- Mr.
+ She will break it to you better than I can.
+; and Emma was quite in charity with him.
+
+ It is a mere nothing after all
+ The doors of the two rooms were just opposite each other.
+ She will break it to you better than I can.
+ I shall just go round by Mrs. Cole 's
+ Here is realization, Here is a man tallied
+ Even pleasure, you know, is fatiguing
+
+ Keep your raptures for Harriet 's face.
+ Ere departing fade from my eyes your forests of bayonets
+ For to one side she leans, Then back she sways
+ It soon appeared that London was not the place for her.
+ Perhaps they had the figure of a winged horse on the prow
+ She will break it to you better than I can.
+
+ She will break it to you better than I can.
+ To conclude, I announce what comes after me.
+; nothing delineated or distinguished.
+ Excelsior Who has gone farthest?
+ To girlhood, boyhood look, the teacher and the school.
+`` How I could so long a time be fancying myself!
+
+`` Yes, sometimes he can.'' Do you mean with regard to this letter?''
+ Any nonsense will serve. the flesh over and over!
+ Eleves, I salute you!`` I not aware!'
+
+
+ + + From 8348fb551ba98141e8cccb1a43955cb31509a87a Mon Sep 17 00:00:00 2001 From: "Michael F. Lamb" Date: Tue, 20 Oct 2015 20:48:22 +0000 Subject: [PATCH 06/14] commit /var/www/tilde.town/template.index.html --- tildetown/templates/frontpage.html | 590 ++++++++++++++++++----------- 1 file changed, 372 insertions(+), 218 deletions(-) diff --git a/tildetown/templates/frontpage.html b/tildetown/templates/frontpage.html index ea52f4b..9761417 100644 --- a/tildetown/templates/frontpage.html +++ b/tildetown/templates/frontpage.html @@ -2,230 +2,101 @@ welcome to tilde town! - + + -

tilde.town is a small unix server built for sharing

-~*~*~* {{active_user_count}} townies active right now *~*~*~ -donate to tilde.town - - - From cb142fe9b82dc155e6173d464e10f10b2a77eb89 Mon Sep 17 00:00:00 2001 From: "Michael F. Lamb" Date: Tue, 20 Oct 2015 21:49:20 +0000 Subject: [PATCH 09/14] update scripts for new /usr/local location --- scripts/active_users.sh | 2 -- scripts/generate_home_page.sh | 19 ++++++++++++------- scripts/stats | 14 ++++++-------- tildetown/stats.py | 26 +++++++++++--------------- 4 files changed, 29 insertions(+), 32 deletions(-) delete mode 100755 scripts/active_users.sh diff --git a/scripts/active_users.sh b/scripts/active_users.sh deleted file mode 100755 index efe4fbb..0000000 --- a/scripts/active_users.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/bash -who | cut -d' ' -f1 | sort -u | wc -l | xargs echo "active_user_count=" | sed 's/ //' diff --git a/scripts/generate_home_page.sh b/scripts/generate_home_page.sh index a806878..cb771ae 100755 --- a/scripts/generate_home_page.sh +++ b/scripts/generate_home_page.sh @@ -1,13 +1,18 @@ #!/bin/bash +# Feed JSON/tdp output from "stats" into mustache template to generate +# tilde.town homepage. Invoke periodically from crontab. + export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games -source /var/local/venvs/tildetown/bin/activate - -stats=/usr/bin/stats -template=/var/local/tildetown/templates/frontpage.html -mustache=/var/local/tildetown/scripts/mustache.hy +template=/usr/local/tildetown-scripts/tildetown/templates/frontpage.html +mustache=/usr/local/tildetown-scripts/tildetown/mustache.py +input_path=/var/www/tilde.town/tilde.json output_path=/var/www/tilde.town/index.html -($stats || echo '{}') | hy $mustache $template > $output_path -deactivate +if [ ! -f "$input_path" ]; then + print "homepage generation needs missing $input_path" + exit 1 +fi + +exec /usr/local/virtualenvs/tildetown/bin/python "$mustache" "$template" < "$input_path" > "$output_path" diff --git a/scripts/stats b/scripts/stats index 29e4b58..1f21b33 100755 --- a/scripts/stats +++ b/scripts/stats @@ -1,8 +1,6 @@ -#!/bin/bash - -cd /var/local - -source venvs/tildetown/bin/activate -output=$(python tildetown/tildetown-py/stats.py) -deactivate -echo $output +#!/bin/sh +# run stats.py in the appropriate virtualenv. +# +# invoke periodically from crontab and direct the output to +# /var/www/tilde.town/tilde.json +exec /usr/local/virtualenvs/tildetown/bin/python /usr/local/tildetown-scripts/tildetown/stats.py diff --git a/tildetown/stats.py b/tildetown/stats.py index be25641..c266d89 100755 --- a/tildetown/stats.py +++ b/tildetown/stats.py @@ -1,6 +1,6 @@ #!/usr/local/bin/python3 -# tdp.py - tilde data in tilde data protocol format. +# stats.py - tilde data in tilde data protocol format. # Copyright 2015 Michael F. Lamb # License: GPLv3+ @@ -14,11 +14,10 @@ It is a JSON structure of the form: 'name': (string) the name of the server. 'url': (string) the URL of the server. 'signup_url': (string) the URL of a page describing the process required to request an account on the server. - 'user_count': (number) the number of users currently registered on the server. 'want_users': (boolean) whether the server is currently accepting new user requests. 'admin_email': (string) the email address of the primary server administrator. 'description': (string) a free-form description for the server. - 'users': [ (array) an array of users on the server. + 'users': [ (array) an array of users on the server, sorted by last activity time { 'username': (string) the username of the user. 'title': (string) the HTML title of the user’s index.html page. @@ -26,30 +25,24 @@ It is a JSON structure of the form: }, ... ] + 'user_count': (number) the number of users currently registered on the server. } -We also overload this with the preexisting data format we were using in -/var/local/tildetown/tildetown-py/stats.py, which is of the form: +We also overload this with some data we were using in the previous version of +stats.py, which is of the form: { - 'all_users': [ (array) of users on the server. + 'users': [ (array) of users on the server. { - 'username': (string) the username of the user. 'default': (boolean) Is the user still using their unmodified default index.html? 'favicon': (string) a url to an image representing the user }, ... ] - 'num_users': (number) count of all_users - 'live_users': [ (array) an array of live users, same format as all_users. Users may appear in both arrays. - ... - ], - 'num_live_users': (number) count of live users + 'live_user_count': (number) count of live users (those who have changed their index.html) 'active_user_count': (number) count of currently logged in users 'generated_at': (string) the time this JSON was generated in '%Y-%m-%d %H:%M:%S' format. 'generated_at_msec': (number) the time this JSON was generated, in milliseconds since the epoch. - 'site_name': (same as 'name' above) - 'site_url': (same as 'url' above) 'uptime': (string) output of `uptime -p` } @@ -148,7 +141,10 @@ def tdp_user(username, homedir): def tdp(): now = datetime.datetime.now() - users = [tdp_user(u, h) for u, h in get_users()] + users = sorted( + (tdp_user(u, h) for u, h in get_users()), + key=lambda x:x['mtime'], + reverse=True) # TDP format data data = { From 5ce87c9aff4c32160dbedd44dbd5b736875fe61a Mon Sep 17 00:00:00 2001 From: "Michael F. Lamb" Date: Tue, 20 Oct 2015 21:51:50 +0000 Subject: [PATCH 10/14] touch a doc typo --- tildetown/stats.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tildetown/stats.py b/tildetown/stats.py index c266d89..3b4d9f6 100755 --- a/tildetown/stats.py +++ b/tildetown/stats.py @@ -46,7 +46,7 @@ stats.py, which is of the form: 'uptime': (string) output of `uptime -p` } -Usage: tdp.py > /var/www/html/tilde.json +Usage: stats.py > /var/www/html/tilde.json """ # I suppose I could import /var/local/tildetown/tildetown-py/stats.py which From f5f27d699c12b53242a145f255965ef31ea1e16a Mon Sep 17 00:00:00 2001 From: "Michael F. Lamb" Date: Tue, 20 Oct 2015 22:27:43 +0000 Subject: [PATCH 11/14] update now-incorrect comments --- tildetown/stats.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tildetown/stats.py b/tildetown/stats.py index 3b4d9f6..af0d0fc 100755 --- a/tildetown/stats.py +++ b/tildetown/stats.py @@ -49,24 +49,12 @@ stats.py, which is of the form: Usage: stats.py > /var/www/html/tilde.json """ -# I suppose I could import /var/local/tildetown/tildetown-py/stats.py which -# does much of the same work, but I wanted to try to make one that needs no -# venv nor 'sh' module. (Success.) Bonus: this runs in 0.127s, vs 5.2s -# for 'stats' - -# FIXME: we output quite a bit of redundant data. I think we should lose -# 'live_users' and do that filtering on the client side. - -# FIXME: If we're the only consumer of the stats.py data, let's change the -# client side to use 'users' and drop 'all_users'. - import datetime import hashlib import json import os import pwd import re -import struct import subprocess SYSTEM_USERS = ['wiki', 'root', 'ubuntu', 'nate', 'nobody'] From 224600a950a8217feb82a0328fcac87ca8dc9f29 Mon Sep 17 00:00:00 2001 From: "Michael F. Lamb" Date: Tue, 20 Oct 2015 22:29:13 +0000 Subject: [PATCH 12/14] remove useless import --- tildetown/stats.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tildetown/stats.py b/tildetown/stats.py index af0d0fc..2061662 100755 --- a/tildetown/stats.py +++ b/tildetown/stats.py @@ -50,7 +50,6 @@ Usage: stats.py > /var/www/html/tilde.json """ import datetime -import hashlib import json import os import pwd From 52a20fce387d1c264aad0c1df7a8a6ee3cbf8f93 Mon Sep 17 00:00:00 2001 From: "Michael F. Lamb" Date: Tue, 20 Oct 2015 22:31:22 +0000 Subject: [PATCH 13/14] --ableism --- tildetown/templates/frontpage.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tildetown/templates/frontpage.html b/tildetown/templates/frontpage.html index ae40e05..546f9f8 100644 --- a/tildetown/templates/frontpage.html +++ b/tildetown/templates/frontpage.html @@ -318,7 +318,7 @@ orators, singers, musicians to come!
  • the homepage userlist is now sorted by modified time
  • there is now a shared
    tweet
    command that all users can use to tweet to the @tildetown account (protip:
    haiku | tweet
    )
  • run
    random_pokemon.sh
    to get a random ascii art pokemon (thanks, ~sanqui)
  • -
  • an insane git-based wiki that all townies can edit (thanks for the help, ~datagrok)
  • +
  • a git-based wiki that all townies can edit (thanks for the help, ~datagrok)
  • an IRC bot (thanks, ~selfsame) that plays numberwang
  • even moar learnings up on the page of ~shanx
  • general good feels
  • From 63ca6c917de4c601f306e01e80a586e014636f2d Mon Sep 17 00:00:00 2001 From: "Michael F. Lamb" Date: Sun, 8 Nov 2015 21:14:55 -0500 Subject: [PATCH 14/14] remove old commented-out news --- tildetown/templates/frontpage.html | 57 ------------------------------ 1 file changed, 57 deletions(-) diff --git a/tildetown/templates/frontpage.html b/tildetown/templates/frontpage.html index 546f9f8..72c5865 100644 --- a/tildetown/templates/frontpage.html +++ b/tildetown/templates/frontpage.html @@ -377,62 +377,5 @@ orators, singers, musicians to come!
    -

    users

    -our esteemed users ({{num_users}})
    -generated at {{generated_at}}
    +

    tilde.town

    +

    is a small unix server made for sharing

    +

    + faq + | sign our guestbook + | signup + | code of conduct + | file help ticket + | donate + | wiki +

    +~*~*~* {{active_user_count}} townies active right now *~*~*~ + + + - - + - -
    +

    our esteemed users

    + ({{num_live_users}} / {{num_users}} shown)
    + generated at {{generated_at}}
    + sorted by recent changes
    -
      - {{#users}} -
    • - {{username}} - {{#default}}(default :3){{/default}} -
    • - {{/users}} -
    -
    -

    what is the tilde.town?

    -

    tilde.town is an intentional community focused on radical inclusivity and the creation of digital art. We strive to create a place that is open to people of all backgrounds and technical ability and strive together to make beautiful works of art that can be conveyed via the web.

    -

    how do i join tilde.town?

    -

    sign up with this fancy form, here! it takes a few days since there is -just one person managing the signups and each user must be manually added. -Please read our code of -conduct and only sign up if you agree to be bound by it.

    -

    sign up form

    -

    what isn't tilde.town?

    -

    it's never super fun to define stuff in a negative sense, but there has been a lot of confusion around what tilde.town is and isn't. tilde.town is not a startup. it is not commercial in any way. tilde.town, as a side effect, has features of a social network but it is not intended to be the "next" anything (except maybe geocities or angelfire). tilde.town is not tilde.club but is inspired by it.

    -

    who is tilde.town?

    -

    tilde.town is made up of its members. we are a group of creative folk -interested in peer education and digital art. the founder is ~vilmibm whom you are more than welcome to -talk at via twitter or email.

    -

    why tilde.town?

    -

    making websites is harder than ever; everything that -can be commercialized is being commercialized; knowledge is being carved up and -locked away for profit; software is increasingly proprietary and bloated. -tilde.town is an experiment in reclaiming a bygone era of low-barrier, -judgement-free, low stakes expression with a focus on low-tech art and -pseudonymous creation.

    -
    -

    tilde town news

    + + full user list +
    +

    this site is an intentional digital community for creating and + sharing works of art, educating peers, and technological + anachronism. we are a completely + non-commercial, donation supported, and + committed to rejecting false technological progress in favor of + empathy and sustainable computing.

    -

    donations! also, new disk

    -

    Wed Apr 29 06:04:58 UTC 2015

    An exciting day for -tilde.town. We now have way to donate via patreon. Thanks to all the -folx who have already become patrons! y'all make the heart of this sysadmin -warm and fuzz. A big part of the push for donations was a need for more server -space which we have as of tonight's server upgrade/reboot. The main tilde.town -server now has a 40gb disk. Enjoy!

    +

    stuff you can do here

    +
      +
    • geocities style hosting
    • +
    • internal irc network
    • +
    • private usenet constellation
    • +
    • internal mail
    • +
    • command line / unix tutelage
    • +
    • make ascii art
    • +
    • host twitter bots
    • +
    • participate in our communal twitter
    • +
    • generate random poetry (under construction)
    • +
    -

    Some updates coming down the pipe: -

      -
    • 2gb quota for all users
    • -
    • fixed poetry server
    • -
    • better signup process/docs
    • -
    -

    + +
     
    -

    welcome haiku

    -

    Thu Mar 5 21:19:42 UTC 2015

    -

    If you signed up in the last two months or so you had a bum welcome present -in your /home. the script has been fixed and now everyone retroactively has a -welcome haiku in their home directory. enjoy.

    - -

    server restart

    -

    Tue Jan 27 21:13:27 UTC 2015

    -

    Hi. Today tilde.town had to restart to pick up a patch for CVE 2015-0235. -data.tilde.town (our poetry server) has also been patched and restated. Sorry -for any inconvenience!

    - -

    lots of people

    -

    Thu Jan 1 07:37:16 UTC 2015

    -

    we have ~370 users. isn't that wild?

    - -

    Scheduled Downtime Tonight

    -

    Wed Nov 26 21:19:12 UTC 2014

    - -

    To accommodate our growing user base, there will be a server resize/reboot -tonight (Pacific time). Sadly I cannot give an exact time as I still don't have -internet at my new place and will have to opportunistically find some to -execute this upgrade.

    -

    The server should only be down for a few minutes, but this will terminate -any running applications (like tmux/screen/irssi). Any files open in an editor -should be preserved by a swap file but you still may want to save and close -things in the next several hours.

    -

    Also, this upgrade means that tilde.town is no longer an essentially free -project, so I may put up something for donations soon.

    - -

    100+ users party report

    -

    Sun Nov 9 23:07:08 UTC 2014 -

    tilde.town now has 102 users. We crossed into three digits last night and -lots of townies hung out in irc to celebrate. Some new features even -launched!

    - -
      -
    • the homepage userlist is now sorted by modified time
    • -
    • there is now a shared
      tweet
      command that all users can use to tweet to the @tildetown account (protip:
      haiku | tweet
      )
    • -
    • run
      random_pokemon.sh
      to get a random ascii art pokemon (thanks, ~sanqui)
    • -
    • an insane git-based wiki that all townies can edit (thanks for the help, ~datagrok)
    • -
    • an IRC bot (thanks, ~selfsame) that plays numberwang
    • -
    • even moar learnings up on the page of ~shanx
    • -
    • general good feels
    • -
    - -

    80 users!

    -

    Wed Oct 29 18:19:45 UTC 2014 - -

    tilde.town just added its 80th user. Welcome! Some folks have been having -trouble with ssh public keys. Remember, public keys are really confusing if you -aren't too familiar with them, and there is no judgement if you can't -immediately get them to work. Feel free to tweet at @tildetown or send an email to ~vilmibm if you'd like some help.

    - -

    - -

    60 users

    -

    Sat Oct 25 19:37:47 UTC 2014 -

    tilde.town is up to 60 users. This is lovely! It is also only a tenth of our -planned total user capacity, so if you are interested in a tilde* account we'd -love to have you. You can even submit a user request with a fancy form now!

    - -

    -submit a user account request! -

    -

    - -

    Change of IP, warnings when you ssh

    -

    Sun Oct 19 03:28:59 UTC 2014

    -

    - In the interest of making sure we don't suddenly disappear from the Internet -as a result of a dynamic IP change on AWS I switched to using an Elastic -IP (amusingly, "elastic" IPs are static). -

    - -

    -The upside is that we now have a static IP (also it's free) (woo). -

    - -

    -The downside is that when you try to SSH into tilde.town, now, you'll get an -error about "something nasty" and there will be many @ characters. You'll want -to edit your .ssh/known_hosts file and remove the entry for tilde.town (your -error message should have a cute copy-pasta-able one-liner for doing this for -you). -

    - -

    -Go ahead and do that, and then log in With Confidence. Hopefully this won't happen again. -

    - -

    -I'll close by mentioning the imminent arrival of many new tildeverse members. We (the tildeverse operators) are just about ready to accept the signups currently languishing in a waitlist. This means lots of new users, which is lovely, but may mean some growing pains while I adapt our server to the new user load in the most cost-effective way. -

    - -
    - - - - + + +
    -
    - Have you guess 'd you yourself would not continue?
    - The wanderer would not heed me
    -`` He told me at parting, that he should soon write
    - Mr. Elton looked all happiness at this proposition
    - what is it to us what the rest do or think?
    - I doubted it more the next day on Box Hill
    -
    - Come thou, arise from the ground unto the place yonder
    - One was the son of Mars, and was killed before Troy
    - He had done his duty and could return to his son.
    - I never saw any thing so outree!
    -; woods, together with mountains, are on fire.
    -`` He told me at parting, that he should soon write
    -
    -`` He told me at parting, that he should soon write
    -; and, abhorring the light, they fly { abroad} by night.
    - Can not you guess what this parcel holds?''
    - And these things I see suddenly, what mean they?
    - And you, paid to defile the People
    - Very strongly may be sincerely fainting.
    -
    - she cried with a most open eagerness
    -`` He told me at parting, that he should soon write
    - Let me hear from you without delay
    - By him she was put in mind of what she might do
    -; but Emma 's countenance was as steady as her words.
    - Dear Miss Woodhouse, do advise me.''
    -
    - It was certainly ‘barbara’ in the eyes of a Greek
    - One can not creep upon a journey
    - One was the son of Mars, and was killed before Troy
    -`` He told me at parting, that he should soon write
    -[ 77 and struck the guilty{ draught} from his mouth.
    -; The golden sun of June declines, It has not caught her eye.
    -
    - Clarke translates ‘miseri senis ore,
    -: naught there is Save body, having property of touch.
    - Alas poor boy, he will never be better,
    -; but if he wished to do it, it might be done.
    -`` He told me at parting, that he should soon write
    - One was the son of Mars, and was killed before Troy
    -
    - I knew who it came from. The virgin shrieks aloud
    - To feel the presence of a brave commanding officer But she was always right.
    - I 'd rather you would.'' This was a river of Troy
    -
    -
    + |~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~| + | ! /\ | X | + | ! //\\ | / \ | + | @@@ ! |~~~~~~~~~~~~~| ///\\\ |/ \| + | @@@@@ /i\|=============| ////\\\\ |\ /| + | @@@ /(i)\====== == ===| /////\\\\\| \ / | + | /((i))\============| //////\\\\\\ X | + | |% % %|=== ===== ==| I||||||||||I / \ | + | |% % %|====== =====| I||||||||||I/ \| + |::: |% # %|============| I||||||||||I\ /| + |::: |% % %|= ====== ===| I||||||||||I \ / | + |::: |% % #|==== ==+++++++++++++|||||||I X | + |:::HHHHHHHHHHHH |% % %|=======! ! ! ! ! ! !|||||||I / \ | + |:::HHHHHH HHHHH |% # %|= =====! ! ! ! ! ! !|||||||I/ \| + |:::HHHHHHHHHHHH |# % %|=== ===! ! ! ! ! ! !|||||||I\ /| + |:::HHH HHHHHHHH |% % %|=======! ! ! ! ! ! !|||||||I \ / | + |:::HHHHHHTTTTTTTTTTTTTTT % #|== = ==! ! ! ! ! ! !|||||||I X | + |:::HHHHHHI [] [] [] [] I # #|=======! ! ! ! ! ! !|||||||I / \ | + |::: HHHHHI [] [] [] [] I % %|==== =! ! ! ! ! ! !|||||||I/ \| + |:::HHHH HI [] [] [] [] I # %|== ====! ! ! ! ! ! !|||||||I\ /| + |:::HHHHHHI [] [] [] [] I % %|=======! ! ! ! ! ! !|||||||I \ / | + |:::HHHHHHI [] [] [] [] I % #|=== = =! ! ! ! ! ! !|||||||I X | + |:::HH HHHI [] [] [] [] I % #| ======! ! ! ! ! ! !|||||||I / \ | + |:::HHHHHHI [] [] [] [] I # #|= = ===! ! ! ! ! ! !|||||||I/ \| + |:::HHHHH I [] [] [] [] I % %|==== ==! ! ! ! ! ! !|||||||I\ /| + |:::HHHHHHI [] [] [] [] I % #|=======! ! ! ! ! ! !|||||||I \ / | + |:::HHHHHHI [] [] [] [] I # #|= =====! ! ! ! ! ! !|||||||I X | + |:::H HHHHI [] [] [] [] I # #|=== = =! ! ! ! ! ! !|||||||I / \ | + |:::HHHHHHI [] [] [] [] I # #|=======! ! ! ! ! ! !|||||||I/ \| + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + o | | | +_|_ | | __| _ _|_ __ _ _ + | | |/ / | |/ | / \_| | |_/ |/ | + |_/|_/|__/\_/|_/|__/o|_/\__/ \/ \/ | |_/ + + +
     orators, singers, musicians to come!
      She will break it to you better than I can.
    @@ -273,10 +144,293 @@ orators, singers, musicians to come!
      Any nonsense will serve. the flesh over and over!
      Eleves, I salute you!`` I not aware!'
     
    +
    +
    + Have you guess 'd you yourself would not continue?
    + The wanderer would not heed me
    +`` He told me at parting, that he should soon write
    + Mr. Elton looked all happiness at this proposition
    + what is it to us what the rest do or think?
    + I doubted it more the next day on Box Hill
    +
    + Come thou, arise from the ground unto the place yonder
    + One was the son of Mars, and was killed before Troy
    + He had done his duty and could return to his son.
    + I never saw any thing so outree!
    +; woods, together with mountains, are on fire.
    +`` He told me at parting, that he should soon write
    +
    +`` He told me at parting, that he should soon write
    +; and, abhorring the light, they fly { abroad} by night.
    + Can not you guess what this parcel holds?''
    + And these things I see suddenly, what mean they?
    + And you, paid to defile the People
    + Very strongly may be sincerely fainting.
    +
    + she cried with a most open eagerness
    +`` He told me at parting, that he should soon write
    + Let me hear from you without delay
    + By him she was put in mind of what she might do
    +; but Emma 's countenance was as steady as her words.
    + Dear Miss Woodhouse, do advise me.''
    +
    + It was certainly ‘barbara’ in the eyes of a Greek
    + One can not creep upon a journey
    + One was the son of Mars, and was killed before Troy
    +`` He told me at parting, that he should soon write
    +[ 77 and struck the guilty{ draught} from his mouth.
    +; The golden sun of June declines, It has not caught her eye.
    +
    + Clarke translates ‘miseri senis ore,
    +: naught there is Save body, having property of touch.
    + Alas poor boy, he will never be better,
    +; but if he wished to do it, it might be done.
    +`` He told me at parting, that he should soon write
    + One was the son of Mars, and was killed before Troy
    +
    + I knew who it came from. The virgin shrieks aloud
    + To feel the presence of a brave commanding officer But she was always right.
    + I 'd rather you would.'' This was a river of Troy
    +
    +
    +

    news

    + +

    Systems status

    +

    Wed Oct 14 13:49:12 PDT 2015

    +

    + ~vilmibm released a rewrite to the server's infrastructure yesterday. Nothing should be different, but it'll be much easier to work on new features and consume fewer resources. +

    +

    + Currently, the guestbook is down. Usenet has also been disabled for now since no one was using it and it has a nontrivial impact on the system. If you want to talk about bringing usenet back, bring it up in irc <3. +

    + + +

    BIRTHDAY! The Town Turns 1

    +

    Sun Oct 11 18:54:35 UTC 2015

    +

    + Exactly a year ago, ~vilmibm gave himself + a birthday present in the form of a small unix server meant for + commnunity and sharing. Now, tilde.town is a thriving community of + feels, peer education and beautiful digital art. +

    +

    + If you are not yet a towner, check out our code of conduct, + look at some user pages, and sign + up!. Everyone is welcome here regardless of skill level and if + making SSH keys is a little scary, that's okay. Reach out to for help. +

    +

    + Here's to another year of html and feels. +

    + +

    new stuff!

    +

    Sat Aug 1 17:27:15 PDT 2015

    +

    + today was a day of things happening! +

      +
    • the first ever tilde.town volunteer admin meeting happened today. ~insom, ~krowbar, and ~vilmibm all met to talk about the future tilde.town and how to ease the burden of things like user signups. Marks the first ever international face-to-face meeting of townies. exciting! +
    • +
    • + guestbook went live! (lol) +
    • +
    • + you can now click on the pretty ascii tilde.town over to the + left to visit a random page (or just go directly + to /cgi/random). +
    • +
    + as always, tilde.town is a place for html and feels. feels run + strong and well today. come say hi! +

    +

    Sun Jul 26 18:01:58 PDT 2015

    +

    new homepage design

    +

    Sun Jul 26 18:01:58 PDT 2015

    +

    + ~vilmibm made a cleaned up homepage. it's linking to two under construction feature--a new help desk for admin requests and a random page linker. there is also a new FAQ. +

    +

    + we've also hit a cool donation milestone of $60. thank you + everyone who has donated! our monthly costs are now covered and if + we hit $65 we can do some more server enhancements. +

    + +

    donations! also, new disk

    +

    Wed Apr 29 06:04:58 UTC 2015

    An exciting day for + tilde.town. We now have way to donate via patreon. Thanks to all the + folx who have already become patrons! y'all make the heart of this sysadmin + warm and fuzz. A big part of the push for donations was a need for more server + space which we have as of tonight's server upgrade/reboot. The main tilde.town + server now has a 40gb disk. Enjoy!

    + +

    Some updates coming down the pipe: +

      +
    • 2gb quota for all users
    • +
    • fixed poetry server
    • +
    • better signup process/docs
    • +
    +

    + +

    welcome haiku

    +

    Thu Mar 5 21:19:42 UTC 2015

    +

    If you signed up in the last two months or so you had a bum welcome present + in your /home. the script has been fixed and now everyone retroactively has a + welcome haiku in their home directory. enjoy.

    + +

    server restart

    +

    Tue Jan 27 21:13:27 UTC 2015

    +

    Hi. Today tilde.town had to restart to pick up a patch for CVE 2015-0235. + data.tilde.town (our poetry server) has also been patched and restated. Sorry + for any inconvenience!

    + +

    lots of people

    +

    Thu Jan 1 07:37:16 UTC 2015

    +

    we have ~370 users. isn't that wild?

    + +

    Scheduled Downtime Tonight

    +

    Wed Nov 26 21:19:12 UTC 2014

    + +

    To accommodate our growing user base, there will be a server resize/reboot + tonight (Pacific time). Sadly I cannot give an exact time as I still don't have + internet at my new place and will have to opportunistically find some to + execute this upgrade.

    +

    The server should only be down for a few minutes, but this will terminate + any running applications (like tmux/screen/irssi). Any files open in an editor + should be preserved by a swap file but you still may want to save and close + things in the next several hours.

    +

    Also, this upgrade means that tilde.town is no longer an essentially free + project, so I may put up something for donations soon.

    + +

    100+ users party report

    +

    Sun Nov 9 23:07:08 UTC 2014 +

    tilde.town now has 102 users. We crossed into three digits last night and + lots of townies hung out in irc to celebrate. Some new features even + launched!

    + +
      +
    • the homepage userlist is now sorted by modified time
    • +
    • there is now a shared
      tweet
      command that all users can use to tweet to the @tildetown account (protip:
      haiku | tweet
      )
    • +
    • run
      random_pokemon.sh
      to get a random ascii art pokemon (thanks, ~sanqui)
    • +
    • an insane git-based wiki that all townies can edit (thanks for the help, ~datagrok)
    • +
    • an IRC bot (thanks, ~selfsame) that plays numberwang
    • +
    • even moar learnings up on the page of ~shanx
    • +
    • general good feels
    • +
    + +

    80 users!

    +

    Wed Oct 29 18:19:45 UTC 2014 + +

    tilde.town just added its 80th user. Welcome! Some folks have been having + trouble with ssh public keys. Remember, public keys are really confusing if you + aren't too familiar with them, and there is no judgement if you can't + immediately get them to work. Feel free to tweet at @tildetown or send an email to ~vilmibm if you'd like some help.

    + +

    + +

    60 users

    +

    Sat Oct 25 19:37:47 UTC 2014 +

    tilde.town is up to 60 users. This is lovely! It is also only a tenth of our + planned total user capacity, so if you are interested in a tilde* account we'd + love to have you. You can even submit a user request with a fancy form now!

    + +

    + submit a user account request! +

    +

    + +

    Change of IP, warnings when you ssh

    +

    Sun Oct 19 03:28:59 UTC 2014

    +

    + In the interest of making sure we don't suddenly disappear from the Internet + as a result of a dynamic IP change on AWS I switched to using an Elastic + IP (amusingly, "elastic" IPs are static). +

    + +

    + The upside is that we now have a static IP (also it's free) (woo). +

    + +

    + The downside is that when you try to SSH into tilde.town, now, you'll get an + error about "something nasty" and there will be many @ characters. You'll want + to edit your .ssh/known_hosts file and remove the entry for tilde.town (your + error message should have a cute copy-pasta-able one-liner for doing this for + you). +

    + +

    + Go ahead and do that, and then log in With Confidence. Hopefully this won't happen again. +

    + +

    + I'll close by mentioning the imminent arrival of many new tildeverse members. We (the tildeverse operators) are just about ready to accept the signups currently languishing in a waitlist. This means lots of new users, which is lovely, but may mean some growing pains while I adapt our server to the new user load in the most cost-effective way. +

    +
    + + From 7217826feb7af3b08d69038f2984787ccdd54586 Mon Sep 17 00:00:00 2001 From: "Michael F. Lamb" Date: Tue, 20 Oct 2015 20:50:28 +0000 Subject: [PATCH 07/14] point generate_home_page at new template path --- scripts/generate_home_page.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/generate_home_page.sh b/scripts/generate_home_page.sh index 5d1935b..a806878 100755 --- a/scripts/generate_home_page.sh +++ b/scripts/generate_home_page.sh @@ -5,7 +5,7 @@ export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/ga source /var/local/venvs/tildetown/bin/activate stats=/usr/bin/stats -template=/var/www/tilde.town/template.index.html +template=/var/local/tildetown/templates/frontpage.html mustache=/var/local/tildetown/scripts/mustache.hy output_path=/var/www/tilde.town/index.html From 37768ae726ea09363c454129b29b5cd05e37f60a Mon Sep 17 00:00:00 2001 From: "Michael F. Lamb" Date: Tue, 20 Oct 2015 21:10:26 +0000 Subject: [PATCH 08/14] make homepage use tdp format --- tildetown/stats.py | 14 +------------- tildetown/templates/frontpage.html | 14 ++++++++------ 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/tildetown/stats.py b/tildetown/stats.py index aee020b..be25641 100755 --- a/tildetown/stats.py +++ b/tildetown/stats.py @@ -135,8 +135,6 @@ def tdp_user(username, homedir): 'title': get_title(index_html), 'mtime': int(most_recent_within(public_html) * 1000), # tilde.town extensions and backward compatibility - # FIXME: just shelling out to diff -q might be way faster than all - # these hashes. 'favicon': 'TODO', 'default': subprocess.call( ['diff', '-q', DEFAULT_HTML_FILENAME, index_html], @@ -176,17 +174,7 @@ def tdp(): 'generated_at': now.strftime('%Y-%m-%d %H:%M:%S'), 'generated_at_msec': int(now.timestamp() * 1000), 'uptime': subprocess.check_output(['uptime', '-p'], universal_newlines=True), - }) - # redundant entries we should drop after changing homepage template - data.update({ - 'all_users': data['users'], - 'num_users': data['user_count'], - 'live_users': [u for u in data['users'] if not u['default']], - 'site_name': data['name'], - 'site_url': data['url'], - }) - data.update({ - 'num_live_users': len(data['live_users']), + 'live_user_count': sum(1 for x in data['users'] if not x['default']), }) return data diff --git a/tildetown/templates/frontpage.html b/tildetown/templates/frontpage.html index 9761417..ae40e05 100644 --- a/tildetown/templates/frontpage.html +++ b/tildetown/templates/frontpage.html @@ -22,16 +22,18 @@

    our esteemed users

    - ({{num_live_users}} / {{num_users}} shown)
    + ({{live_user_count}} / {{user_count}} shown)
    generated at {{generated_at}}
    sorted by recent changes
      - {{#live_users}} -
    • - {{username}} -
    • - {{/live_users}} + {{#users}} + {{^default}} +
    • + {{username}} +
    • + {{/default}} + {{/users}}
    full user list
    - -