Mercurial > hg > index.fcgi > www > www-1
changeset 118:65db090a697e
laterlinks3: add GCS support
author | paulo |
---|---|
date | Fri, 18 Sep 2020 01:13:29 -0700 |
parents | 476cb019ad9f |
children | 0a20081612b9 |
files | laterlinks3/Dockerfile laterlinks3/laterlinks_flask_app.py |
diffstat | 2 files changed, 90 insertions(+), 50 deletions(-) [+] |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/laterlinks3/Dockerfile Fri Sep 18 01:13:29 2020 -0700 1.3 @@ -0,0 +1,17 @@ 1.4 +# Use the official lightweight Python image. 1.5 +# https://hub.docker.com/_/python 1.6 +FROM python:3.6-slim 1.7 + 1.8 +# Copy local code to the container image. 1.9 +ENV APP_HOME /app 1.10 +WORKDIR $APP_HOME 1.11 +COPY . ./ 1.12 + 1.13 +# Install production dependencies. 1.14 +RUN pip install -r requirements.pip 1.15 + 1.16 +# Run the web service on container startup. Here we use the gunicorn 1.17 +# webserver, with one worker process and 8 threads. 1.18 +# For environments with multiple CPU cores, increase the number of workers 1.19 +# to be equal to the cores available. 1.20 +CMD exec gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 laterlinks_flask_app:app
2.1 --- a/laterlinks3/laterlinks_flask_app.py Tue Sep 08 23:52:57 2020 -0700 2.2 +++ b/laterlinks3/laterlinks_flask_app.py Fri Sep 18 01:13:29 2020 -0700 2.3 @@ -1,14 +1,17 @@ 2.4 import csv 2.5 import datetime 2.6 +import io 2.7 import os 2.8 +import tempfile 2.9 2.10 import flask 2.11 - 2.12 +import google.cloud.storage 2.13 from html3.html3 import HTML 2.14 2.15 app = flask.Flask(__name__) 2.16 2.17 -PIN = os.environ.get('LLPIN') 2.18 +GCS_BUCKET = google.cloud.storage.Client().get_bucket(os.environ.get("GCS_BUCKET")) 2.19 +PIN = os.environ.get("LLPIN") 2.20 STRTIME_FMT = "%Y-%m-%d %H:%M:%S" 2.21 2.22 2.23 @@ -39,30 +42,47 @@ 2.24 return "MISSING FIELD(s)!" 2.25 2.26 2.27 -def lldb_unread_load(): 2.28 - return csv.reader(open(LLDB_UNREAD_FN), LLDIALECT) 2.29 +def gcs_download(fn): 2.30 + tmp_f = tempfile.TemporaryFile("w+") 2.31 + blob = GCS_BUCKET.get_blob(fn) 2.32 + if blob: 2.33 + tmp_f.write(str(blob.download_as_string(), encoding="utf-8")) 2.34 + return tmp_f 2.35 2.36 2.37 -def lldb_add(inp): 2.38 +def gcs_upload(fn, tmp_f): 2.39 + blob = GCS_BUCKET.blob(fn) 2.40 + blob.upload_from_file(tmp_f, rewind=True) 2.41 + 2.42 + 2.43 +def lldb_unread_load(lldb_unread_tmp_f): 2.44 + lldb_unread_tmp_f.seek(0) 2.45 + return csv.reader(lldb_unread_tmp_f, LLDIALECT) 2.46 + 2.47 + 2.48 +def lldb_add(inp, lldb_tmp_f, lldb_unread_tmp_f): 2.49 title = inp.get("title") 2.50 url = inp.get("url") 2.51 if not (title and url): 2.52 raise MissingFieldsError() 2.53 2.54 dt_str = datetime.datetime.now().strftime(STRTIME_FMT) 2.55 - with open(LLDB_FN, 'a') as lldb_f: 2.56 - csv.writer(lldb_f, LLDIALECT).writerow([title, url, dt_str]) 2.57 - with open(LLDB_UNREAD_FN, 'a') as lldb_f: 2.58 - csv.writer(lldb_f, LLDIALECT).writerow([title, url, dt_str]) 2.59 2.60 + lldb_tmp_f.seek(0, io.SEEK_END) 2.61 + csv.writer(lldb_tmp_f, LLDIALECT).writerow([title, url, dt_str]) 2.62 + gcs_upload(LLDB_FN, lldb_tmp_f) 2.63 2.64 -def lldb_unread_delete(inp): 2.65 + lldb_unread_tmp_f.seek(0, io.SEEK_END) 2.66 + csv.writer(lldb_unread_tmp_f, LLDIALECT).writerow([title, url, dt_str]) 2.67 + gcs_upload(LLDB_UNREAD_FN, lldb_unread_tmp_f) 2.68 + 2.69 + 2.70 +def lldb_unread_delete(inp, lldb_unread_tmp_f): 2.71 delete = inp.getlist("delete") 2.72 if not delete: 2.73 raise MissingFieldsError() 2.74 2.75 - lldb_unread = [i for i in lldb_unread_load()] 2.76 - lldb_unread_f = open(LLDB_UNREAD_FN, 'w') 2.77 + lldb_unread = [i for i in lldb_unread_load(lldb_unread_tmp_f)] 2.78 2.79 try: 2.80 for i in delete: 2.81 @@ -71,9 +91,10 @@ 2.82 if i == dt_str: 2.83 lldb_unread.remove(j) 2.84 finally: 2.85 - csv.writer(lldb_unread_f, LLDIALECT).writerows(lldb_unread) 2.86 - lldb_unread_f.close() 2.87 - 2.88 + lldb_unread_tmp_f.truncate(0) 2.89 + lldb_unread_tmp_f.seek(0) 2.90 + csv.writer(lldb_unread_tmp_f, LLDIALECT).writerows(lldb_unread) 2.91 + gcs_upload(LLDB_UNREAD_FN, lldb_unread_tmp_f) 2.92 2.93 2.94 @app.route("/", methods=["GET", "POST"]) 2.95 @@ -82,46 +103,48 @@ 2.96 inp = flask.request.form 2.97 cookies = flask.request.cookies 2.98 2.99 - if is_post: 2.100 - if not PIN: 2.101 - raise PinSetupError 2.102 - elif cookies.get("llpin") != PIN: 2.103 - raise PinFailError 2.104 + with gcs_download(LLDB_UNREAD_FN) as lldb_unread_tmp_f: 2.105 + if is_post: 2.106 + if not PIN: 2.107 + raise PinSetupError 2.108 + elif cookies.get("llpin") != PIN: 2.109 + raise PinFailError 2.110 2.111 - if inp["submit"] == "Add": 2.112 - lldb_add(inp) 2.113 - elif inp["submit"] == "Delete": 2.114 - lldb_unread_delete(inp) 2.115 + if inp["submit"] == "Add": 2.116 + with gcs_download(LLDB_FN) as lldb_tmp_f: 2.117 + lldb_add(inp, lldb_tmp_f, lldb_unread_tmp_f) 2.118 + elif inp["submit"] == "Delete": 2.119 + lldb_unread_delete(inp, lldb_unread_tmp_f) 2.120 2.121 - title = "later links..." 2.122 - root = HTML("html") 2.123 + title = "later links..." 2.124 + root = HTML("html") 2.125 2.126 - header = root.head 2.127 - header.link(rel="stylesheet", type="text/css", href=flask.url_for("static", filename="index.css")) 2.128 - header.title(title) 2.129 - 2.130 - body = root.body 2.131 - body.h1(title) 2.132 + header = root.head 2.133 + header.link(rel="stylesheet", type="text/css", href=flask.url_for("static", filename="index.css")) 2.134 + header.title(title) 2.135 + 2.136 + body = root.body 2.137 + body.h1(title) 2.138 2.139 - form = body.form(action="/", method="post") 2.140 + form = body.form(action="/", method="post") 2.141 2.142 - table = form.table 2.143 - hrow = table.tr 2.144 - hrow.th("Link") 2.145 - hrow.th("Created") 2.146 - hrow.th.input(type="submit", name="submit", value="Delete") 2.147 + table = form.table 2.148 + hrow = table.tr 2.149 + hrow.th("Link") 2.150 + hrow.th("Created") 2.151 + hrow.th.input(type="submit", name="submit", value="Delete") 2.152 2.153 - for (title, url, dt_str) in lldb_unread_load(): 2.154 - row = table.tr 2.155 - row.td.a(title, href=url) 2.156 - row.td(dt_str) 2.157 - row.td.input(type="checkbox", name="delete", value=dt_str) 2.158 + for (title, url, dt_str) in lldb_unread_load(lldb_unread_tmp_f): 2.159 + row = table.tr 2.160 + row.td.a(title, href=url) 2.161 + row.td(dt_str) 2.162 + row.td.input(type="checkbox", name="delete", value=dt_str) 2.163 2.164 - p1 = form.p 2.165 - p1.label("Title").input(type="text", name="title", size="64") 2.166 - p1.br 2.167 - p1.label("URL").input(type="text", name="url", size="64") 2.168 - p1.br 2.169 - p1.input(type="submit", name="submit", value="Add") 2.170 + p1 = form.p 2.171 + p1.label("Title").input(type="text", name="title", size="64") 2.172 + p1.br 2.173 + p1.label("URL").input(type="text", name="url", size="64") 2.174 + p1.br 2.175 + p1.input(type="submit", name="submit", value="Add") 2.176 2.177 - return str(root).encode("utf-8") 2.178 + return str(root).encode("utf-8")