Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
339 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
redis: | ||
host: 127.0.0.1 | ||
port: 6379 | ||
db: 7 | ||
minsize: 1 | ||
maxsize: 5 | ||
|
||
host: 127.0.0.1 | ||
port: 9002 |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
redis: | ||
image: redis:4 | ||
ports: | ||
- 6379:6379 |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
import os | ||
import re | ||
|
||
from setuptools import find_packages, setup | ||
|
||
|
||
def read_version(): | ||
regexp = re.compile(r"^__version__\W*=\W*'([\d.abrc]+)'") | ||
init_py = os.path.join(os.path.dirname(__file__), | ||
'shortify', '__init__.py') | ||
with open(init_py) as f: | ||
for line in f: | ||
match = regexp.match(line) | ||
if match is not None: | ||
return match.group(1) | ||
else: | ||
msg = 'Cannot find version in shortify/__init__.py' | ||
raise RuntimeError(msg) | ||
|
||
|
||
install_requires = [ | ||
'aiohttp', | ||
'trafaret', | ||
'aiohttp_jinja2', | ||
'pyyaml', | ||
'aioredis==1.0.0b2' | ||
] | ||
|
||
|
||
setup(name='shortify', | ||
version=read_version(), | ||
description='Url shortener for aiohttp', | ||
platforms=['POSIX'], | ||
packages=find_packages(), | ||
include_package_data=True, | ||
install_requires=install_requires, | ||
zip_safe=False) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
__version__ = '0.0.1' |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
from shortify.main import main | ||
|
||
main() |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import asyncio | ||
import logging | ||
import pathlib | ||
|
||
import aiohttp_jinja2 | ||
import jinja2 | ||
from aiohttp import web | ||
|
||
from shortify.routes import setup_routes | ||
from shortify.utils import init_redis, load_config | ||
from shortify.views import SiteHandler | ||
|
||
|
||
PROJ_ROOT = pathlib.Path(__file__).parent.parent | ||
TEMPLATES_ROOT = pathlib.Path(__file__).parent / 'templates' | ||
|
||
|
||
async def setup_redis(app, conf, loop): | ||
pool = await init_redis(conf['redis'], loop) | ||
|
||
async def close_redis(app): | ||
pool.close() | ||
await pool.wait_closed() | ||
|
||
app.on_cleanup.append(close_redis) | ||
app['redis_pool'] = pool | ||
return pool | ||
|
||
|
||
def setup_jinja(app): | ||
loader = jinja2.FileSystemLoader(str(TEMPLATES_ROOT)) | ||
jinja_env = aiohttp_jinja2.setup(app, loader=loader) | ||
return jinja_env | ||
|
||
|
||
async def init(loop): | ||
conf = load_config(PROJ_ROOT / 'config' / 'config.yml') | ||
|
||
app = web.Application(loop=loop) | ||
redis_pool = await setup_redis(app, conf, loop) | ||
setup_jinja(app) | ||
|
||
handler = SiteHandler(redis_pool, conf) | ||
|
||
setup_routes(app, handler, PROJ_ROOT) | ||
host, port = conf['host'], conf['port'] | ||
return app, host, port | ||
|
||
|
||
def main(): | ||
logging.basicConfig(level=logging.DEBUG) | ||
|
||
loop = asyncio.get_event_loop() | ||
app, host, port = loop.run_until_complete(init(loop)) | ||
web.run_app(app, host=host, port=port) | ||
|
||
|
||
if __name__ == '__main__': | ||
main() |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
def setup_routes(app, handler, project_root): | ||
router = app.router | ||
h = handler | ||
router.add_get('/', h.index, name='index') | ||
router.add_get('/{short_id}', h.redirect, name='short') | ||
router.add_post('/shortify', h.shotify, name='shortfy') | ||
router.add_static( | ||
'/static/', path=str(project_root / 'static'), | ||
name='static') |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<title>shortify - aiohttp url shortener</title> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
|
||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.98.0/css/materialize.min.css"> | ||
<link rel=stylesheet type=text/css href="{{ url('static', filename='css/custom.css') }}"> | ||
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> | ||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> | ||
</head> | ||
|
||
<script type="text/javascript"> | ||
$(function() { | ||
$('#submitButton').click(function() { | ||
$.ajax({ | ||
type: "POST", | ||
url: "/shortify", | ||
data: JSON.stringify({'url' : $('#url').val()}), | ||
success: returnSuccess, | ||
dataType: 'json', | ||
contentType: "application/json", | ||
}); | ||
}); | ||
}); | ||
|
||
function returnSuccess(data, textStatus, jqXHR) { | ||
if(data.url) { | ||
$('#url-result').text(data.url); | ||
$('#url').val(""); | ||
$("a").attr("href", data.url) | ||
} else { | ||
$('#url-result').text("Please enter a URL!"); | ||
} | ||
} | ||
</script> | ||
|
||
<body> | ||
<div id="wrap"> | ||
<header> | ||
<h1><a href="">shortify</a></h1> | ||
<p>aiohttp URL shortener demo</p> | ||
</header> | ||
<div class="container"> | ||
<div class="row"> | ||
<div class="col s12"> | ||
<input type="text" name="url" id="url" class="form-control input-sm" placeholder="http://www.google.com" /> | ||
</div> | ||
</div> | ||
<div class="row"> | ||
<div class="col s4 offset-s4"> | ||
<button id="submitButton" class="waves-effect waves-light btn-large blue darken-1">Shorten</button> | ||
</div> | ||
</div> | ||
<div class="row"> | ||
<div class="col s12"> | ||
<div class="panel-footer"> | ||
<h4> | ||
<a href="#" id="url-result">Enter URL</a> | ||
</h4> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
<footer><a href="https://github.com/aio-libs">https://github.com/aio-libs</a></footer> | ||
</body> | ||
</html> |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import aioredis | ||
import trafaret as t | ||
import yaml | ||
from aiohttp import web | ||
|
||
|
||
def load_config(fname): | ||
with open(fname, 'rt') as f: | ||
data = yaml.load(f) | ||
# TODO: add config validation | ||
return data | ||
|
||
|
||
async def init_redis(conf, loop): | ||
pool = await aioredis.create_redis_pool( | ||
(conf['host'], conf['port']), | ||
minsize=conf['minsize'], | ||
maxsize=conf['maxsize'], | ||
loop=loop | ||
) | ||
return pool | ||
|
||
|
||
CHARS = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789" | ||
|
||
|
||
def encode(num, alphabet=CHARS): | ||
if num == 0: | ||
return alphabet[0] | ||
arr = [] | ||
base = len(alphabet) | ||
while num: | ||
num, rem = divmod(num, base) | ||
arr.append(alphabet[rem]) | ||
arr.reverse() | ||
return ''.join(arr) | ||
|
||
|
||
ShortifyRequest = t.Dict({ | ||
t.Key('url'): t.URL | ||
}) | ||
|
||
|
||
def fetch_url(data): | ||
try: | ||
data = ShortifyRequest(data) | ||
except t.DataError: | ||
raise web.HTTPBadRequest('URL is not valid') | ||
return data['url'] |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import aiohttp_jinja2 | ||
from aiohttp import web | ||
|
||
from .utils import encode, fetch_url | ||
|
||
|
||
class SiteHandler: | ||
|
||
def __init__(self, redis, conf): | ||
self._redis = redis | ||
self._conf = conf | ||
|
||
@aiohttp_jinja2.template('index.html') | ||
async def index(self, request): | ||
return {} | ||
|
||
@aiohttp_jinja2.template('timeline.html') | ||
async def shotify(self, request): | ||
data = await request.json() | ||
long_url = fetch_url(data) | ||
|
||
index = await self._redis.incr("shortify:count") | ||
path = encode(index) | ||
key = "shortify:{}".format(path) | ||
await self._redis.set(key, long_url) | ||
|
||
url = "http://{host}:{port}/{path}".format( | ||
host=self._conf['host'], | ||
port=self._conf['port'], | ||
path=path) | ||
|
||
return web.json_response({"url": url}) | ||
|
||
async def redirect(self, request): | ||
short_id = request.match_info['short_id'] | ||
key = 'shortify:{}'.format(short_id) | ||
location = await self._redis.get(key) | ||
if not location: | ||
raise web.HTTPNotFound() | ||
return web.HTTPFound(location=location.decode()) |
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
* { | ||
margin: 0; | ||
} | ||
|
||
html, body { | ||
height: 100%; | ||
} | ||
|
||
#content { | ||
margin-top: 20px; | ||
margin-bottom: 60px; | ||
} | ||
|
||
header { | ||
margin-bottom: 30px; | ||
padding-bottom: 10px; | ||
clear: both; | ||
} | ||
|
||
#wrap { | ||
margin: 5px 10px -50px 10px; | ||
padding: 10px; | ||
text-align: center; | ||
min-height: 100%; | ||
} | ||
#url-result { | ||
color: #039be5; | ||
display: hidden; | ||
} | ||
|
||
.btn { | ||
float: right; | ||
} | ||
|
||
footer { | ||
color: #039be5; | ||
text-align: center; | ||
height: 50px; | ||
line-height: 50px; | ||
} | ||
|
||
footer a{ | ||
color: #039be5; | ||
} |
Large diffs are not rendered by default.
Oops, something went wrong.
Binary file not shown.
Binary file not shown.