mirror of
https://github.com/paradoxxxzero/butterfly.git
synced 2026-06-03 19:09:42 +00:00
Port to tornado
This commit is contained in:
@@ -1,4 +1,33 @@
|
||||
from flask import Flask
|
||||
app = Flask(__name__)
|
||||
import os
|
||||
import tornado.web
|
||||
import tornado.options
|
||||
import tornado.web
|
||||
|
||||
from . import routes
|
||||
|
||||
application = tornado.web.Application(
|
||||
debug=tornado.options.options.debug,
|
||||
cookie_secret=tornado.options.options.secret,
|
||||
static_path=os.path.join(os.path.dirname(__file__), "static"),
|
||||
template_path=os.path.join(os.path.dirname(__file__), "templates")
|
||||
)
|
||||
|
||||
|
||||
class url(object):
|
||||
def __init__(self, url):
|
||||
self.url = url
|
||||
|
||||
def __call__(self, cls):
|
||||
application.add_handlers(
|
||||
r'.*$',
|
||||
(tornado.web.url(self.url, cls, name=cls.__name__),)
|
||||
)
|
||||
return cls
|
||||
|
||||
|
||||
class Route(tornado.web.RequestHandler):
|
||||
@property
|
||||
def log(self):
|
||||
return log
|
||||
|
||||
|
||||
import app.routes
|
||||
|
||||
@@ -1,7 +1,22 @@
|
||||
from . import app
|
||||
from flask import render_template
|
||||
import tornado.websocket
|
||||
from app import url, Route
|
||||
|
||||
@url(r'/')
|
||||
class Index(Route):
|
||||
def get(self):
|
||||
return self.render('index.html')
|
||||
|
||||
|
||||
@url(r'/ws')
|
||||
class EchoWebSocket(Route, tornado.websocket.WebSocketHandler):
|
||||
|
||||
def open(self):
|
||||
log.info('Websocket opened')
|
||||
|
||||
def on_message(self, message):
|
||||
self.write_message(message)
|
||||
|
||||
def on_close(self):
|
||||
log.info('Websocket closed')
|
||||
|
||||
|
||||
@app.route("/")
|
||||
def index():
|
||||
return render_template('index.jinja2')
|
||||
|
||||
91
app/templates/_base.html
Normal file
91
app/templates/_base.html
Normal file
@@ -0,0 +1,91 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<link rel="shortcut icon" href="{{ static_url('images/favicon.png') }}">
|
||||
{% include "_ie.html" %}
|
||||
|
||||
<title>Apparatus</title>
|
||||
<link href="{{ static_url('stylesheets/bootstrap/bootstrap.css') }}" rel="stylesheet">
|
||||
<link href="{{ static_url('stylesheets/main.css') }}" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
{% include "_nav.html" %}
|
||||
|
||||
<section id="myCarousel" class="carousel slide" data-ride="carousel">
|
||||
<ol class="carousel-indicators">
|
||||
<li data-target="#myCarousel" data-slide-to="0" class="active"></li>
|
||||
<li data-target="#myCarousel" data-slide-to="1"></li>
|
||||
<li data-target="#myCarousel" data-slide-to="2"></li>
|
||||
</ol>
|
||||
<div class="carousel-inner">
|
||||
{% for i in range(3) %}
|
||||
<article class="item{{ ' active' if i == 0 else '' }}">
|
||||
<div class="container">
|
||||
<div class="carousel-caption">
|
||||
<h1>Title</h1>
|
||||
<p>Venenatis nullam purus fusce sed et, pellentesque dolor venenatis at donec. Pretium quam, rhoncus sed tempus dictum. Neque ut tincidunt vestibulum vel et, inceptos vestibulum blandit, pellentesque praesent sit. Posuere in praesent, volutpat accumsan felis ut veritatis metus, leo amet purus pede semper in ornare. Convallis sollicitudin at dapibus, phasellus eros felis aliquet nulla amet, in in et tristique enim. Justo gravida nulla rhoncus, faucibus est in lacus sollicitudin fringilla sed, aliquet eu magna morbi lectus nulla pede. Mi pellentesque dictumst nam suspendisse vero. Metus ut elit mauris sollicitudin elit, malesuada semper pede elementum. Id aliquet magna consequat nulla, erat amet et pharetra lacinia quisque vitae. Suspendisse luctus, in malesuada pellentesque, porta dui orci dui eget lorem. </p>
|
||||
<p>
|
||||
<a class="btn btn-lg btn-primary" href="#" role="button">Okay</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{% end %}
|
||||
</div>
|
||||
<a class="left carousel-control" href="#myCarousel" data-slide="prev">
|
||||
<span class="glyphicon glyphicon-chevron-left"></span>
|
||||
</a>
|
||||
<a class="right carousel-control" href="#myCarousel" data-slide="next">
|
||||
<span class="glyphicon glyphicon-chevron-right"></span>
|
||||
</a>
|
||||
</section>
|
||||
|
||||
<section class="container">
|
||||
<article class="row">
|
||||
{% for i in range(3) %}
|
||||
<div class="col-lg-4">
|
||||
<h2>Title</h2>
|
||||
<p>Lorem ipsum dolor sit amet, aliquet porttitor tortor mattis nec mauris, duis nunc accumsan vel. Eget neque suspendisse nonummy turpis, tempus urna cum vestibulum lectus. Ut elit lectus neque, elementum nulla curabitur faucibus, qui augue cubilia. Neque erat nullam ullamco massa habitasse dolor, erat at sed donec vulputate sodales. Et elementum arcu vel blandit ultrices, eu quam, eget nunc ultricies quam tincidunt aenean. Et sem massa ac, egestas justo tempus nam nulla ac mauris, est neque maecenas imperdiet per ipsum. A beatae neque et incidunt mollis ipsum. Nulla lorem. Ullamcorper quisque commodo elit a elementum, suscipit etiam faucibus ante, suspendisse aliquet sed non, nec tellus mauris. Purus urna euismod, viverra etiam dis elit, phasellus quam wisi posuere lorem porttitor, pulvinar consequat nec eu fringilla malesuada. Nec leo dignissim lacus egestas nunc, lorem magna, sodales laoreet dignissim. A facilisis, quisque tristique lorem, gravida risus etiam, in lacinia, congue et nunc at.</p>
|
||||
<p><a class="btn btn-default" href="#" role="button">View details »</a></p>
|
||||
</div>
|
||||
{% end %}
|
||||
</article>
|
||||
|
||||
<hr class="featurette-divider">
|
||||
{% for i in range(3) %}
|
||||
<article class="row featurette">
|
||||
{% if i % 2 %}
|
||||
<div class="col-md-5">
|
||||
<img src="http://lorempixel.com/g/400/400#{{ i }}" />
|
||||
</div>
|
||||
{% end %}
|
||||
<div class="col-md-7">
|
||||
<h2 class="featurette-heading">Title <span class="text-muted">Subtitle</span></h2>
|
||||
<p class="lead">Lead</p>
|
||||
</div>
|
||||
{% if i % 2 == 0 %}
|
||||
<div class="col-md-5">
|
||||
<img src="http://lorempixel.com/g/400/400#{{ i }}" />
|
||||
</div>
|
||||
{% end %}
|
||||
<hr class="featurette-divider">
|
||||
</article>
|
||||
{% end %}
|
||||
|
||||
<footer>
|
||||
<p class="pull-right"><a href="#">Back to top</a></p>
|
||||
<p>© 2013 Company, Inc. · <a href="#">Privacy</a> · <a href="#">Terms</a></p>
|
||||
</footer>
|
||||
</section>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
|
||||
<script src="{{ static_url('javascripts/bootstrap.min.js') }}"></script>
|
||||
<script src="{{ static_url('javascripts/main.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,93 +0,0 @@
|
||||
{%- from "_utils.jinja2" import static -%}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="">
|
||||
<meta name="author" content="">
|
||||
<link rel="shortcut icon" href="{{ static('images/favicon.png') }}">
|
||||
{%- include "_ie.jinja2" -%}
|
||||
|
||||
<title>Apparatus</title>
|
||||
<link href="{{ static('stylesheets/bootstrap/bootstrap.css') }}" rel="stylesheet">
|
||||
<link href="{{ static('stylesheets/main.css') }}" rel="stylesheet">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
{%- include "_nav.jinja2" -%}
|
||||
|
||||
<section id="myCarousel" class="carousel slide" data-ride="carousel">
|
||||
<ol class="carousel-indicators">
|
||||
<li data-target="#myCarousel" data-slide-to="0" class="active"></li>
|
||||
<li data-target="#myCarousel" data-slide-to="1"></li>
|
||||
<li data-target="#myCarousel" data-slide-to="2"></li>
|
||||
</ol>
|
||||
<div class="carousel-inner">
|
||||
{% for i in range(3) %}
|
||||
<article class="item{{ ' active' if i == 0}}">
|
||||
<div class="container">
|
||||
<div class="carousel-caption">
|
||||
<h1>{{ lipsum(1, html=False, max=30) }}</h1>
|
||||
{{ lipsum(1, max=40) }}
|
||||
<p>
|
||||
<a class="btn btn-lg btn-primary" href="#" role="button">{{ lipsum(1, html=False, min=1, max=3) }}</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<a class="left carousel-control" href="#myCarousel" data-slide="prev">
|
||||
<span class="glyphicon glyphicon-chevron-left"></span>
|
||||
</a>
|
||||
<a class="right carousel-control" href="#myCarousel" data-slide="next">
|
||||
<span class="glyphicon glyphicon-chevron-right"></span>
|
||||
</a>
|
||||
</section>
|
||||
|
||||
<section class="container">
|
||||
<article class="row">
|
||||
{% for i in range(3) %}
|
||||
<div class="col-lg-4">
|
||||
<h2>{{ lipsum(1, html=False, min=5, max=10) }}</h2>
|
||||
{{ lipsum(1, max=40) }}
|
||||
<p><a class="btn btn-default" href="#" role="button">View details »</a></p>
|
||||
</div>
|
||||
{% endfor %}
|
||||
</article>
|
||||
|
||||
<hr class="featurette-divider">
|
||||
{% macro item(i) %}
|
||||
{% if i % 2 %}
|
||||
<div class="col-md-5">
|
||||
<img src="http://lorempixel.com/g/400/400#{{ i }}" />
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="col-md-7">
|
||||
<h2 class="featurette-heading">{{ lipsum(1, html=False, min=3, max=6) }}<span class="text-muted">{{ lipsum(1, html=False, min=3, max=6) }}</span></h2>
|
||||
<p class="lead">{{ lipsum(1, html=False, max=50) }}</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
{% for i in range(3) %}
|
||||
<article class="row featurette">
|
||||
{{ item(i) }}
|
||||
{{ item(i + 11) }}
|
||||
<hr class="featurette-divider">
|
||||
</article>
|
||||
{% endfor %}
|
||||
|
||||
<footer>
|
||||
<p class="pull-right"><a href="#">Back to top</a></p>
|
||||
<p>© 2013 Company, Inc. · <a href="#">Privacy</a> · <a href="#">Terms</a></p>
|
||||
</footer>
|
||||
</section>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-1.10.2.min.js"></script>
|
||||
<script src="{{ static('javascripts/bootstrap.min.js') }}"></script>
|
||||
<script src="{{ static('javascripts/main.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,3 +0,0 @@
|
||||
{% macro static(fn) %}
|
||||
{{ url_for('static', filename=fn) }}
|
||||
{% endmacro %}
|
||||
1
app/templates/index.html
Normal file
1
app/templates/index.html
Normal file
@@ -0,0 +1 @@
|
||||
{% extends "_base.html" %}
|
||||
@@ -1 +0,0 @@
|
||||
{%- extends "_base.jinja2" -%}
|
||||
@@ -1,5 +1,4 @@
|
||||
wdb
|
||||
log_colorizer
|
||||
wsreload
|
||||
cutter
|
||||
pytest
|
||||
|
||||
@@ -1 +1 @@
|
||||
flask
|
||||
tornado
|
||||
|
||||
60
serve.py
60
serve.py
@@ -1,53 +1,49 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
host = 'apparatus.l'
|
||||
port = 2001
|
||||
url = "http://%s:%d/*" % (host, port)
|
||||
|
||||
from log_colorizer import colorize
|
||||
colorize()
|
||||
|
||||
try:
|
||||
from wdb.ext import add_w_builtin
|
||||
add_w_builtin()
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
import logging
|
||||
from app import app
|
||||
app.logger.setLevel(logging.DEBUG)
|
||||
import tornado.options
|
||||
import tornado.ioloop
|
||||
|
||||
del app.logger.handlers[:]
|
||||
tornado.options.define("secret", default='secret', help="Secret")
|
||||
tornado.options.define("debug", default=True, help="Debug mode")
|
||||
tornado.options.define("host", default='apparatus.l', help="Server host")
|
||||
tornado.options.define("port", default=2001, type=int, help="Server port")
|
||||
|
||||
logging.getLogger('werkzeug').setLevel(logging.DEBUG)
|
||||
host = 'apparatus.l'
|
||||
tornado.options.parse_command_line()
|
||||
|
||||
werkzeug_debugger = True
|
||||
try:
|
||||
from wdb.ext import WdbMiddleware
|
||||
except ImportError:
|
||||
app.logger.debug('wdb not found')
|
||||
else:
|
||||
app.wsgi_app = WdbMiddleware(app.wsgi_app, start_disabled=True)
|
||||
werkzeug_debugger = False
|
||||
|
||||
from logging import getLogger
|
||||
log = getLogger('apparatus')
|
||||
log.setLevel(10 if tornado.options.options.debug else 30)
|
||||
|
||||
log.debug('Starting server')
|
||||
ioloop = tornado.ioloop.IOLoop.instance()
|
||||
|
||||
|
||||
from app import application
|
||||
application.listen(tornado.options.options.port)
|
||||
|
||||
|
||||
url = "http://%s:%d/*" % (
|
||||
tornado.options.options.host, tornado.options.options.port)
|
||||
|
||||
try:
|
||||
from wsreload.client import monkey_patch_http_server, watch
|
||||
from wsreload.client import sporadic_reload, watch
|
||||
except ImportError:
|
||||
app.logger.debug('wsreload not found')
|
||||
log.debug('wsreload not found')
|
||||
else:
|
||||
def log(httpserver):
|
||||
app.logger.debug('WSReloaded after server restart')
|
||||
monkey_patch_http_server({'url': url}, callback=log)
|
||||
app.logger.debug('HTTPServer monkey patched for url %s' % url)
|
||||
sporadic_reload({'url': url})
|
||||
|
||||
files = ['app/static/javascripts/',
|
||||
'app/static/stylesheets/',
|
||||
'app/templates/']
|
||||
watch({'url': url}, files, unwatch_at_exit=True)
|
||||
|
||||
app.run(
|
||||
debug=True,
|
||||
host=host,
|
||||
port=port,
|
||||
use_debugger=werkzeug_debugger,
|
||||
threaded=True)
|
||||
log.debug('Starting loop')
|
||||
ioloop.start()
|
||||
|
||||
Reference in New Issue
Block a user