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
|
#### Other Changes
|
||||||
|
|
||||||
- A client certificate can now have an empty ``commonName`` field.
|
- A client certificate can now have an empty ``commonName`` field.
|
||||||
- For the ``JetforceApplication``, named capture groups in a route's regex
|
- ``JetforceApplication.route()`` - named capture groups in regex patterns will
|
||||||
pattern will now be passed as keyword arguments to the wrapped function. See
|
now be passed as keyword arguments to the wrapped function. See
|
||||||
examples/pagination.py for an example of how to use this feature.
|
examples/pagination.py for an example of how to use this feature.
|
||||||
- A ``CompositeApplication`` class is now included to support virtual hosting
|
- ``CompositeApplication`` - A class is now included to support composing
|
||||||
by composing multiple applications behind the same jetforce server. See
|
composing multiple applications behind the same jetforce server. See
|
||||||
examples/vhost.py for an example of how to use this feature.
|
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.
|
their intended usage as defined in RFC 3875.
|
||||||
- CGI variables - ``TLS_CIPHER`` and ``TLS_VERSION`` have been added and
|
- CGI variables - ``TLS_CIPHER`` and ``TLS_VERSION`` have been added and
|
||||||
contain information about the established TLS connection.
|
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)
|
### 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.
|
retrieve their response by parsing the URL query string.
|
||||||
|
|
||||||
This example stores the guestbook inside of a persistent sqlite database.
|
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
|
import sqlite3
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from jetforce import GeminiServer, JetforceApplication, Response, Status
|
from jetforce import GeminiServer, JetforceApplication, Response, Status
|
||||||
|
|
||||||
DB = "/tmp/guestbook.sqlite"
|
db = sqlite3.connect("/tmp/guestbook.sqlite", detect_types=sqlite3.PARSE_DECLTYPES)
|
||||||
|
|
||||||
SCHEMA = """
|
SCHEMA = """
|
||||||
CREATE TABLE IF NOT EXISTS guestbook (
|
CREATE TABLE IF NOT EXISTS guestbook (
|
||||||
|
@ -25,8 +20,7 @@ CREATE TABLE IF NOT EXISTS guestbook (
|
||||||
message TEXT
|
message TEXT
|
||||||
)
|
)
|
||||||
"""
|
"""
|
||||||
with sqlite3.connect(DB) as c:
|
db.execute(SCHEMA)
|
||||||
c.execute(SCHEMA)
|
|
||||||
|
|
||||||
|
|
||||||
app = JetforceApplication()
|
app = JetforceApplication()
|
||||||
|
@ -36,16 +30,14 @@ app = JetforceApplication()
|
||||||
def index(request):
|
def index(request):
|
||||||
lines = ["Guestbook", "=>/submit Sign the Guestbook"]
|
lines = ["Guestbook", "=>/submit Sign the Guestbook"]
|
||||||
|
|
||||||
with sqlite3.connect(DB, detect_types=sqlite3.PARSE_DECLTYPES) as c:
|
for row in db.execute("SELECT * FROM guestbook ORDER BY created_at"):
|
||||||
for row in c.execute("SELECT * FROM guestbook ORDER BY created_at"):
|
ip_address, created_at, message = row
|
||||||
ip_address, created_at, message = row
|
line = f"{created_at:%Y-%m-%d} - [{ip_address}] {message}"
|
||||||
line = f"{created_at:%Y-%m-%d} - [{ip_address}] {message}"
|
lines.append("")
|
||||||
lines.append("")
|
lines.append(line)
|
||||||
lines.append(line)
|
|
||||||
|
|
||||||
lines.extend(["", "...", ""])
|
lines.extend(["", "...", ""])
|
||||||
body = "\n".join(lines)
|
body = "\n".join(lines)
|
||||||
|
|
||||||
return Response(Status.SUCCESS, "text/gemini", body)
|
return Response(Status.SUCCESS, "text/gemini", body)
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,9 +47,8 @@ def submit(request):
|
||||||
message = request.query[:256]
|
message = request.query[:256]
|
||||||
created = datetime.now()
|
created = datetime.now()
|
||||||
ip_address = request.environ["REMOTE_HOST"]
|
ip_address = request.environ["REMOTE_HOST"]
|
||||||
with sqlite3.connect(DB) as c:
|
values = (ip_address, created, message)
|
||||||
values = (ip_address, created, message)
|
db.execute("INSERT INTO guestbook VALUES (?, ?, ?)", values)
|
||||||
c.execute("INSERT INTO guestbook VALUES (?, ?, ?)", values)
|
|
||||||
return Response(Status.REDIRECT_TEMPORARY, "")
|
return Response(Status.REDIRECT_TEMPORARY, "")
|
||||||
else:
|
else:
|
||||||
return Response(Status.INPUT, "Enter your message (max 256 characters)")
|
return Response(Status.INPUT, "Enter your message (max 256 characters)")
|
||||||
|
|
|
@ -106,13 +106,12 @@ class GeminiProtocol(LineOnlyReceiver):
|
||||||
# Yield control of the event loop
|
# Yield control of the event loop
|
||||||
await deferLater(self.server.reactor, 0)
|
await deferLater(self.server.reactor, 0)
|
||||||
while True:
|
while True:
|
||||||
try:
|
data = await maybeDeferred(response_generator.__next__)
|
||||||
data = await maybeDeferred(response_generator.__next__)
|
if data is None:
|
||||||
self.write_body(data)
|
|
||||||
# Yield control of the event loop
|
|
||||||
await deferLater(self.server.reactor, 0)
|
|
||||||
except StopIteration:
|
|
||||||
break
|
break
|
||||||
|
self.write_body(data)
|
||||||
|
# Yield control of the event loop
|
||||||
|
await deferLater(self.server.reactor, 0)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.server.log_message(traceback.format_exc())
|
self.server.log_message(traceback.format_exc())
|
||||||
self.write_status(Status.CGI_ERROR, "An unexpected error occurred")
|
self.write_status(Status.CGI_ERROR, "An unexpected error occurred")
|
||||||
|
|
Loading…
Reference in New Issue