Last active
May 25, 2024 23:23
-
-
Save Justasic/5c461096b0d7ec8ba290dda6e3d74f1f to your computer and use it in GitHub Desktop.
Actually URLShortener.tac but no syntax highlighting. This is an entire website for storing and redirecting URLs in a simple way. Post JSON to the site and it stores it, give someone a link and it redirects them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/twistd3 -noy | |
import sqlite3, json, os | |
from twisted.application import service, internet | |
from twisted.web import static, server, proxy | |
from twisted.internet import reactor | |
from twisted.python import log | |
from klein import Klein | |
class ShortURL: | |
""" | |
# ShortURL (https://github.com/delight-im/ShortURL) | |
# Copyright (c) delight.im (https://www.delight.im/) | |
# Licensed under the MIT License (https://opensource.org/licenses/MIT) | |
ShortURL: Bijective conversion between natural numbers (IDs) and short strings | |
ShortURL.encode() takes an ID and turns it into a short string | |
ShortURL.decode() takes a short string and turns it into an ID | |
Features: | |
+ large alphabet (51 chars) and thus very short resulting strings | |
+ proof against offensive words (removed 'a', 'e', 'i', 'o' and 'u') | |
+ unambiguous (removed 'I', 'l', '1', 'O' and '0') | |
Example output: | |
123456789 <=> pgK8p | |
""" | |
_alphabet = '23456789bcdfghjkmnpqrstvwxyzBCDFGHJKLMNPQRSTVWXYZ-_' | |
_base = len(_alphabet) | |
def encode(self, number): | |
string = '' | |
while(number > 0): | |
string = self._alphabet[number % self._base] + string | |
number //= self._base | |
return string | |
def decode(self, string): | |
number = 0 | |
for char in string: | |
number = number * self._base + self._alphabet.index(char) | |
return number | |
class NotFound(Exception): | |
pass | |
class UserError(Exception): | |
pass | |
class ServerError(Exception): | |
pass | |
class Page(object): | |
app = Klein() | |
encoder = ShortURL() | |
DEFAULT_PATH = os.path.join(os.path.dirname(__file__), 'urls.db') | |
conn = sqlite3.connect(DEFAULT_PATH) | |
@app.handle_errors(NotFound) | |
def notfound(self, request, failure): | |
request.setResponseCode(404) | |
return 'Not found, I say!' | |
@app.handle_errors(UserError) | |
def usererr(self, request, failure): | |
request.setResponseCode(400) | |
return 'You input invalid data.' | |
@app.handle_errors(ServerError) | |
def servererr(self, request, failure): | |
request.setResponseCode(500) | |
return 'OOps! We messed up! Maybe try again?' | |
@app.route("/", methods=['POST']) | |
def CreateShortURL(self, request): | |
data = json.loads(request.content.read()) | |
self.conn.execute("CREATE TABLE IF NOT EXISTS ShortURLs(url TEXT NOT NULL)").execute("INSERT INTO ShortURLs (url) VALUES (?)", (data['url'],)) | |
rowid = self.conn.execute("SELECT ROWID FROM ShortURLs WHERE url=?", (data['url'],)) | |
id = rowid.fetchone() | |
if not id: | |
request.setResponseCode(500) | |
return json.dumps({"status": "Failure", "reason": "Database commitment failed."}) | |
eid = self.encoder.encode(id[0]) | |
request.setResponseCode(200) | |
return json.dumps({"status": "Success", "id": eid, "site": "https://s.justasic.net/"}) | |
@app.route("/<shortid>") | |
def RedirectURL(self, request, shortid): | |
shortid = shortid.strip() | |
if not shortid: | |
raise NotFound() | |
try: | |
id = self.encoder.decode(shortid) | |
cur = self.conn.execute("SELECT url FROM ShortURLs WHERE ROWID=?", (id,)) | |
url = cur.fetchone() | |
if not url: | |
raise NotFound() | |
return request.redirect(url[0]) | |
except sqlite3.OperationalError: | |
raise NotFound() | |
except ValueError: | |
raise UserError() | |
application = service.Application("URLShortener") | |
herp = Page() | |
w = server.Site(herp.app.resource()) | |
i = internet.TCPServer(6099, w) | |
i.setServiceParent(application) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment