Updating changelog and fixing examples

This commit is contained in:
Michael Lazar 2020-05-26 00:25:48 -04:00
parent 8d7a3372c0
commit 9c5eb99266
3 changed files with 21 additions and 29 deletions

View File

@ -65,16 +65,18 @@ variable.
#### Other Changes
- A client certificate can now have an empty ``commonName`` field.
- For the ``JetforceApplication``, named capture groups in a route's regex
pattern will now be passed as keyword arguments to the wrapped function. See
- ``JetforceApplication.route()`` - named capture groups in regex patterns will
now be passed as keyword arguments to the wrapped function. See
examples/pagination.py for an example of how to use this feature.
- A ``CompositeApplication`` class is now included to support virtual hosting
by composing multiple applications behind the same jetforce server. See
- ``CompositeApplication`` - A class is now included to support composing
composing multiple applications behind the same jetforce server. See
examples/vhost.py for an example of how to use this feature.
- CGI variables - ``SCRIPT_NAME`` and ``PATH_INfO`` have been changed to match
- CGI variables - ``SCRIPT_NAME`` and ``PATH_INFO`` have been changed to match
their intended usage as defined in RFC 3875.
- CGI variables - ``TLS_CIPHER`` and ``TLS_VERSION`` have been added and
contain information about the established TLS connection.
- Applications can now optionally return ``Deferred`` objects instead of bytes,
in order to support full-blown asynchronous coroutines.
### v0.2.3 (2020-05-24)

View File

@ -5,18 +5,13 @@ This is an example of how to return a 10 INPUT request to the client and
retrieve their response by parsing the URL query string.
This example stores the guestbook inside of a persistent sqlite database.
Because each request will run inside of a separate thread, we must create a new
connection object inside of the request handler instead of re-using a global
database connection. This thread-safety can be disabled in sqlite3 by using the
check_same_thread=False argument, but then it's up to you to ensure that only
connection request is writing to the database at any given time.
"""
import sqlite3
from datetime import datetime
from jetforce import GeminiServer, JetforceApplication, Response, Status
DB = "/tmp/guestbook.sqlite"
db = sqlite3.connect("/tmp/guestbook.sqlite", detect_types=sqlite3.PARSE_DECLTYPES)
SCHEMA = """
CREATE TABLE IF NOT EXISTS guestbook (
@ -25,8 +20,7 @@ CREATE TABLE IF NOT EXISTS guestbook (
message TEXT
)
"""
with sqlite3.connect(DB) as c:
c.execute(SCHEMA)
db.execute(SCHEMA)
app = JetforceApplication()
@ -36,16 +30,14 @@ app = JetforceApplication()
def index(request):
lines = ["Guestbook", "=>/submit Sign the Guestbook"]
with sqlite3.connect(DB, detect_types=sqlite3.PARSE_DECLTYPES) as c:
for row in c.execute("SELECT * FROM guestbook ORDER BY created_at"):
ip_address, created_at, message = row
line = f"{created_at:%Y-%m-%d} - [{ip_address}] {message}"
lines.append("")
lines.append(line)
for row in db.execute("SELECT * FROM guestbook ORDER BY created_at"):
ip_address, created_at, message = row
line = f"{created_at:%Y-%m-%d} - [{ip_address}] {message}"
lines.append("")
lines.append(line)
lines.extend(["", "...", ""])
body = "\n".join(lines)
return Response(Status.SUCCESS, "text/gemini", body)
@ -55,9 +47,8 @@ def submit(request):
message = request.query[:256]
created = datetime.now()
ip_address = request.environ["REMOTE_HOST"]
with sqlite3.connect(DB) as c:
values = (ip_address, created, message)
c.execute("INSERT INTO guestbook VALUES (?, ?, ?)", values)
values = (ip_address, created, message)
db.execute("INSERT INTO guestbook VALUES (?, ?, ?)", values)
return Response(Status.REDIRECT_TEMPORARY, "")
else:
return Response(Status.INPUT, "Enter your message (max 256 characters)")

View File

@ -106,13 +106,12 @@ class GeminiProtocol(LineOnlyReceiver):
# Yield control of the event loop
await deferLater(self.server.reactor, 0)
while True:
try:
data = await maybeDeferred(response_generator.__next__)
self.write_body(data)
# Yield control of the event loop
await deferLater(self.server.reactor, 0)
except StopIteration:
data = await maybeDeferred(response_generator.__next__)
if data is None:
break
self.write_body(data)
# Yield control of the event loop
await deferLater(self.server.reactor, 0)
except Exception:
self.server.log_message(traceback.format_exc())
self.write_status(Status.CGI_ERROR, "An unexpected error occurred")