Updating changelog and fixing examples
This commit is contained in:
parent
8d7a3372c0
commit
9c5eb99266
12
CHANGELOG.md
12
CHANGELOG.md
|
@ -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)
|
||||
|
||||
|
|
|
@ -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)")
|
||||
|
|
|
@ -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")
|
||||
|
|
Loading…
Reference in New Issue