Permalink
Browse files

app: 'I'm feeling random' random page, select from a given url list '…

…url timestamp'

container launch: catch any exceptions after creation and before start and attempt to dispose of container
ui: move about/how block right below buttons, text edits, make font bigger
  • Loading branch information...
1 parent 3148d69 commit d949902c4f8535410167cd14a2d6f597f5cc1aa2 @ikreymer ikreymer committed Dec 3, 2015
Showing with 116 additions and 73 deletions.
  1. +2 −0 app/config.yaml
  2. +83 −41 app/main.py
  3. +1 −0 app/static/dropdown.css
  4. +1 −1 app/static/main.css
  5. +27 −31 app/templates/index.html
  6. +1 −0 docker-compose.yml
  7. +1 −0 run-local.sh
View
@@ -18,6 +18,8 @@ image_prefix: netcapsule
default_browser: firefox
+random_page_file: /app/urls.txt
+
redirect_paths:
'': firefox
'ie': ie5.5
View
@@ -15,9 +15,12 @@
import json
import random
+import traceback
+
from uwsgidecorators import timer
import uwsgi
+
#=============================================================================
class DockerController(object):
def _load_config(self):
@@ -56,6 +59,13 @@ def __init__(self):
self.default_browser = config['default_browser']
self.redirect_paths = config['redirect_paths']
+ self.randompages = []
+ try:
+ with open(config['random_page_file']) as fh:
+ self.randompages = list([line.rstrip() for line in fh])
+ except Exception as e:
+ print(e)
+
self.redis = redis.StrictRedis(host=self.REDIS_HOST)
self.redis.setnx('next_client', '1')
@@ -116,40 +126,49 @@ def new_container(self, browser_id, env=None, default_host=None):
ports=[self.VNC_PORT, self.CMD_PORT],
environment=env,
)
- id_ = container.get('Id')
-
- res = self.cli.start(container=id_,
- port_bindings={self.VNC_PORT: None, self.CMD_PORT: None},
- volumes_from=['netcapsule_shared_data_1'],
- network_mode='netcapsule',
- )
-
- info = self.cli.inspect_container(id_)
- ip = info['NetworkSettings']['IPAddress']
- if not ip:
- ip = info['NetworkSettings']['Networks']['netcapsule']['IPAddress']
-
- short_id = id_[:12]
- self.redis.hset('all_containers', short_id, ip)
- self.redis.setex('c:' + short_id, self.C_EXPIRE_TIME, 1)
+ short_id = None
+ try:
+ id_ = container.get('Id')
+ short_id = id_[:12]
+
+ res = self.cli.start(container=id_,
+ port_bindings={self.VNC_PORT: None, self.CMD_PORT: None},
+ volumes_from=['netcapsule_shared_data_1'],
+ network_mode='netcapsule',
+ )
+
+ info = self.cli.inspect_container(id_)
+ ip = info['NetworkSettings']['IPAddress']
+ if not ip:
+ ip = info['NetworkSettings']['Networks']['netcapsule']['IPAddress']
+
+ self.redis.hset('all_containers', short_id, ip)
+ self.redis.setex('c:' + short_id, self.C_EXPIRE_TIME, 1)
+
+ return {'vnc_host': self._get_host_port(info, self.VNC_PORT, default_host),
+ 'cmd_host': self._get_host_port(info, self.CMD_PORT, default_host),
+ }
+ except Exception as e:
+ if short_id:
+ self.remove_container(short_id)
- return {'vnc_host': self._get_host_port(info, self.VNC_PORT, default_host),
- 'cmd_host': self._get_host_port(info, self.CMD_PORT, default_host),
- }
+ traceback.print_exc(e)
+ return {}
- def remove_container(self, short_id, ip):
+ def remove_container(self, short_id, ip=None):
print('REMOVING ' + short_id)
try:
self.cli.remove_container(short_id, force=True)
except Exception as e:
- print(e)
+ traceback.print_exc(e)
self.redis.hdel('all_containers', short_id)
self.redis.delete('c:' + short_id)
- ip_keys = self.redis.keys(ip + ':*')
- for key in ip_keys:
- self.redis.delete(key)
+ if ip:
+ ip_keys = self.redis.keys(ip + ':*')
+ for key in ip_keys:
+ self.redis.delete(key)
def remove_all(self, check_expired=False):
all_containers = self.redis.hgetall('all_containers')
@@ -244,6 +263,32 @@ def throttle(self):
return False
+ def do_init(self, browser, url, ts, host, client_id):
+ env = {}
+ env['URL'] = url
+ env['TS'] = ts
+ env['SCREEN_WIDTH'] = os.environ.get('SCREEN_WIDTH')
+ env['SCREEN_HEIGHT'] = os.environ.get('SCREEN_HEIGHT')
+ env['REDIS_HOST'] = dc.REDIS_HOST
+ env['PYWB_HOST_PORT'] = dc.PYWB_HOST + ':8080'
+ env['BROWSER'] = browser
+
+ info = self.timed_new_container(browser, env, host, client_id)
+ info['queue'] = 0
+ return info
+
+ def get_randompage(self):
+ if not self.randompages:
+ return '/'
+
+ url, ts = random.choice(self.randompages).split(' ', 1)
+ print(url, ts)
+ path = random.choice(self.browser_paths.keys())
+ return '/' + path + '/' + ts + '/' + url
+
+
+# Routes Below
+# ===================
@route('/static/<filepath:path>')
def server_static(filepath):
@@ -261,33 +306,20 @@ def init_container():
browser = request.query.get('browser')
url = request.query.get('url')
ts = request.query.get('ts')
- resp = do_init(browser, url, ts, host, client_id)
+ resp = dc.do_init(browser, url, ts, host, client_id)
else:
resp = {'queue': queue_pos, 'id': client_id}
response.headers['Cache-Control'] = 'no-cache, no-store, max-age=0, must-revalidate'
return resp
-def do_init(browser, url, ts, host, client_id):
- env = {}
- env['URL'] = url
- env['TS'] = ts
- env['SCREEN_WIDTH'] = os.environ.get('SCREEN_WIDTH')
- env['SCREEN_HEIGHT'] = os.environ.get('SCREEN_HEIGHT')
- env['REDIS_HOST'] = dc.REDIS_HOST
- env['PYWB_HOST_PORT'] = dc.PYWB_HOST + ':8080'
- env['BROWSER'] = browser
-
- info = dc.timed_new_container(browser, env, host, client_id)
- info['queue'] = 0
- return info
-
@route(['/', '/index.html', '/index.htm'])
@jinja2_view('index.html', template_lookup=['templates'])
def index():
return {}
+
@route(['/<path>/<ts:re:[0-9-]+>/<url:re:.*>', '/<path>/<url:re:.*>'])
@jinja2_view('replay.html', template_lookup=['templates'])
def route_load_url(path='', url='', ts=''):
@@ -321,13 +353,23 @@ def route_load_url(path='', url='', ts=''):
'browser': browser_info}
-def onexit():
- dc.remove_all(False)
+@route('/random')
+def randompage():
+ redirect(dc.get_randompage())
+
+
+# Init
+# ======================
dc = DockerController()
application = default_app()
+
+# Shutdown containers on exit?
+#def onexit():
+# dc.remove_all(False)
+
#uwsgi.atexit = onexit
def init_cleanup_timer(dc, expire_time):
@@ -10,6 +10,7 @@
border-radius: 4px;
box-shadow: 4px 4px 8px rgba(0,0,0,0.4);
position: relative;
+ font-size: 13px;
}
.dropdown-button {
View
@@ -53,7 +53,7 @@ iframe {
/* front page */
-#frontpage {font-size: 13px;}
+#frontpage {font-size: 14px;}
#frontpage h1 {
margin-bottom: 3rem;
@@ -120,47 +120,43 @@ <h1 class="logo"><span class="colors">oldweb</span>.today</h1>
</div>
<div id="invalid-form">Please select a browser, url and a date.</div>
<button type="submit" class="button-primary">Surf The Old Web!</button>
+ <a class="button" href="/random">I'm feeling Random!</a>
+ <div class="fold">
+ <label><a>About / How it works</a></label>
+ <div>
+ <strong>oldweb.today</strong> is built with open source tools:
+ <ul>
+ <li><a href="https://www.docker.com/">Docker containers</a> to manage user sessions and scale across machines.</li>
+
+ <li><a href="https://www.winehq.org/">Wine</a>, <a href="http://basilisk.cebix.net/">Basilisk</a> and <a href="http://sheepshaver.cebix.net/">Sheepshaver</a> emulators are used to run old browsers on legacy platforms.</li>
+
+ <li><a href="https://github.com/ikreymer/pywb">pywb</a> is used as the web archive replay proxy system.</li>
+
+ <li><a href="https://kanaka.github.io/noVNC/">noVNC</a> provides VNC support in HTML over Websockets.</li>
+
+ <li>The <a href="http://mementoweb.org/about/">Memento Web API</a> and <a href="https://github.com/oduwsdl/memgator">MemGator</a> are used to communicate with web archives.</li>
+ <li>Random page list compiled with help from <a href="https://twitter.com/muffinista">@muffinista</a></li>
+ </ul>
+ <br>
+ <a href="https://github.com/ikreymer/netcapsule">Full source code available on Github.</a><br>
+ <br>
+ The archived web pages are available courtesy of these public web archives:
+ {% include 'archives-list.html' %}
+ <br>
+ <br>
+ </div>
+ </div>
</form>
<div class="row" class="section">
<div class="seven columns">
- <p style="display: none">
- Session time limit: <strong id="session-limit">10 minutes</strong>.<br>
- Active users: <strong id="number-users">56</strong> of <strong id="max-users">100</strong>.
- </p>
- A project by <a href="https://github.com/ikreymer">Ilya Kreymer</a>, with support from
+ A project by <a href="https://github.com/ikreymer">Ilya Kreymer</a>, with support from:
<div class="support">
<a class="support shuttleworth" href="https://www.shuttleworthfoundation.org/"><img src="/static/shuttleworth-tiny.png" alt="Shuttleworth Foundation"></a>
<a class="support rhizome" href="http://rhizome.org/"><img src="/static/rhizome-tiny.png" alt="Rhizome"></a>
</div>
<div>Contact: oldweb.today@rhizome.org</div>
-
- <div>
- <h2>About / How it works</h2>
- <div>
- <strong>oldweb.today</strong> is built with open source tools:
- <ul>
- <li><a href="https://www.docker.com/">Docker containers</a> to manage user sessions and scale across machines.</li>
-
- <li><a href="https://www.winehq.org/">Wine</a>, <a href="http://basilisk.cebix.net/">Basilisk</a> and <a href="http://sheepshaver.cebix.net/">Sheepshaver</a> emulators are used to run old browsers on legacy platforms.</li>
-
- <li><a href="https://github.com/ikreymer/pywb">pywb (Python Wayback)</a> is used as the web replay proxy system.</li>
-
- <li><a href="https://kanaka.github.io/noVNC/">noVNC</a> provides VNC support in HTML over Websockets.</li>
-
- <li>The <a href="http://timetravel.mementoweb.org/guide/api/">Memento API</a> and <a href="https://github.com/oduwsdl/memgator">MemGator</a> are used to communicate with web archives.</li>
- </ul>
- <br>
- <a href="https://github.com/ikreymer/netcapsule">Full source code available on Github.</a><br>
- <br>
- The archived web pages are available courtesy of these public web archives:
- {% include 'archives-list.html' %}
- <br>
- <br>
- </div>
- </div>
-
</div>
</div>
View
@@ -56,6 +56,7 @@ app:
volumes:
- /var/run/docker.sock:/var/run/docker.sock
+ - ${RANDOM_URL_LIST}:/app/urls.txt
environment:
- SCREEN_WIDTH=1024
View
@@ -1,5 +1,6 @@
#export ARCHIVE_JSON=http://webenact.rhizome.org/collinfo.json
export ARCHIVE_JSON=./archives.gen.json
+export RANDOM_URL_LIST=./urls.txt
python -c "import yaml; import json; data = yaml.load(open('archives.yaml')); open('$ARCHIVE_JSON', 'w').write(json.dumps(data))"
docker-compose --x-networking build
docker-compose --x-networking up -d

0 comments on commit d949902

Please sign in to comment.