1 Star 0 Fork 0

gsw945/site-clumsy

Create your Gitee Account
Explore and code with more than 12 million developers,Free private repositories !:)
Sign up
文件
This repository doesn't specify license. Please pay attention to the specific project description and its upstream code dependency when using it.
Clone or Download
run.py 15.90 KB
Copy Edit Raw Blame History
gsw945 authored 2017-11-20 00:43 . 初步实现文章修改
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
# -*- coding: utf-8 -*-
import os
import json
import uuid
import collections
from datetime import datetime
from functools import wraps
import socket
import traceback
import logging
import threading
from multiprocessing.dummy import (
Pool as ThreadPool,
Lock
)
import sys
import signal
import multiprocessing as mp
from werkzeug.routing import BaseConverter
from werkzeug.local import LocalProxy
from flask import (
Flask,
g,
session,
render_template,
render_template_string,
redirect,
url_for,
current_app,
abort,
request,
make_response,
jsonify
)
import psutil
import pytz
from dbhelper import DBHelper
from visit_record import VisitRecord
from print_log_client import print_log
_is_debug = False
if len(sys.argv) > 1:
if '--debug' in sys.argv[1:]:
_is_debug = True
SEP = os.linesep
ROOT = os.path.dirname(os.path.abspath(__file__))
template_folder = os.path.join(ROOT, 'frontend/templates')
static_folder = os.path.join(ROOT, 'frontend/static')
app = Flask(
__name__,
template_folder=template_folder,
static_folder=static_folder
)
app.config['SECRET_KEY'] = 'gsw945 website secret ^_^'
app.debug = _is_debug
db_file = os.path.join(ROOT, 'data.sqlite')
uri = 'sqlite:///{0}'.format(db_file)
app.db = DBHelper(uri)
vr_file = os.path.join(ROOT, 'visit-record.sqlite')
vr_uri = 'sqlite:///{0}'.format(vr_file)
cpu_count = psutil.cpu_count()
tz = pytz.timezone('Asia/Shanghai')
def print_log_server(port=10909):
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
addr = ('0.0.0.0', port)
log_file = os.path.join(ROOT, 'print.log')
start_msg = 'udp log server listen at [{0}:{1}]'.format(addr[0], addr[1])
with open(log_file,'a') as f:
f.write(start_msg)
f.write(SEP)
print(start_msg)
try:
sock.bind(addr)
while True:
data, address = sock.recvfrom(4096)
if bool(data):
# sent = sock.sendto(data, address)
msg = data.decode('utf-8', 'ignore')
# print('get data [{0}]'.format(msg))
with open(log_file,'a') as f:
f.write(msg)
f.write(SEP)
except (KeyboardInterrupt, SystemExit, Exception):
# print(traceback.format_exc())
print('=' * 60, sep='')
traceback.print_exc()
print('=' * 60)
finally:
sock.close()
def update_logger(logger, log_file=None):
# refer: https://docs.python.org/3.5/library/logging.html#logrecord-attributes
formatter = logging.Formatter(
fmt='\n'.join([
'[%(name)s] %(asctime)s.%(msecs)d',
'\t%(pathname)s [line: %(lineno)d]',
'\t%(processName)s[%(process)d] => %(threadName)s[%(thread)d] => %(module)s.%(filename)s:%(funcName)s()',
'\t%(levelname)s: %(message)s\n'
]),
datefmt='%Y-%m-%d %H:%M:%S'
)
if log_file is None:
log_file = 'logger.log'
# stream_handler = logging.StreamHandler()
# stream_handler.setFormatter(formatter)
# logger.addHandler(stream_handler)
file_handler = logging.FileHandler(log_file, mode='a', encoding='utf-8')
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
logger.setLevel(logging.DEBUG)
return logger
app_obj = LocalProxy(lambda: current_app._get_current_object())
app_db = LocalProxy(lambda: current_app.db.db)
app_tpp = LocalProxy(lambda: current_app.tpp)
_logger = logging.getLogger('flask.app')
new_logger = update_logger(_logger)
tp_lock = None
log_port = None
ts_fmt = '%Y-%m-%d %H:%M:%S.%f'
class RegexConverter(BaseConverter):
def __init__(self, _map, *args):
self.map = _map
self.regex = args[0]
app.url_map.converters['regex'] = RegexConverter
def get_http_exception_handler(app):
"""
# refer: https://stackoverflow.com/questions/29332056/global-error-handler-for-any-exception#44083675
Overrides the default http exception handler to return JSON.
"""
handle_http_exception = app.handle_http_exception
@wraps(handle_http_exception)
def ret_val(exception):
exc = handle_http_exception(exception)
is_ajax = request.headers.get('X-Requested-With', None) == 'XMLHttpRequest'
is_api = 'X-Api' in request.headers
resp = ''
err = {
'code': exc.code,
'name': exc.name,
'description': exc.description
}
if is_ajax or is_api:
resp = jsonify(err)
else:
tmpl = ''.join([
'<!DOCTYPE html>',
'<html>',
'<head>',
'<title>{{ code }} {{ name }}</title>',
'</head>',
'<body>',
'<h2>{{ code }} {{ name }}</h2>',
'<p>{{ description }}</p>',
'<p>&#8674;&#8608; <a href="/">Home Page</a></p>'
'</body>',
'</html>'
])
resp = render_template_string(tmpl, **err)
return resp, exc.code
return ret_val
# Override the HTTP exception handler.
app.handle_http_exception = get_http_exception_handler(app)
def log_visit_record(vr_uri, vr_data, lock=None, log_port=None):
thread = threading.current_thread()
print(thread)
lock.acquire()
vr_db = VisitRecord(vr_uri)
records = vr_db.db['records']
affect = records.insert(vr_data)
vr_db.close()
if affect > 0:
print_log('write visit record log completed', log_port)
else:
print_log('write visit record log failed', log_port)
lock.release()
return None
@app.before_request
def before_request():
global app_obj
if app_obj.debug:
app_obj.jinja_env.cache = {}
print('before request')
@app.after_request
def after_request(response):
g.is_static = request.endpoint == 'static'
if not g.is_static:
coks = request.cookies
_uid = coks.get('uid', None)
regular = True
if _uid is None:
regular = False
_uid = uuid.uuid5(uuid.NAMESPACE_DNS, '').hex
_max_age = 3600 * 24 * 30 * 12 # 1 year
response.set_cookie('uid', _uid, max_age=_max_age)
g.uid = _uid
g.regular = regular
g.ts_now = datetime.now(tz).strftime(ts_fmt)
print('after request')
return response
@app.teardown_request
def teardown_request(exception):
if not g.is_static:
global app_tpp
global tp_lock
global vr_uri
global log_port
global tz
global ts_fmt
hdrs = request.headers
full_path = request.full_path
is_xhr = request.is_xhr
method = request.method
scheme = request.scheme
referer = hdrs.get('Referer', request.referrer)
x_real_ip = hdrs.get('X-Real-Ip', request.remote_addr)
x_forwarded_for = hdrs.get('X-Forwarded-For', None)
accept_language = hdrs.get('Accept-Language', request.accept_languages)
host = hdrs.get('Host', request.host)
user_agent = hdrs.get('User-Agent', request.user_agent)
uid = g.uid
regular = g.regular
dt_str = g.ts_now
vr_data = {
'uid': uid,
'regular': regular,
'method': method,
'is_xhr': is_xhr,
'scheme': scheme,
'host': host,
'x_real_ip': x_real_ip,
'full_path': full_path,
'referer': referer,
'x_forwarded_for': x_forwarded_for,
'accept_language': accept_language,
'user_agent': user_agent,
'dt_str': dt_str
}
apply_data = {
'lock': tp_lock,
'log_port': log_port
}
# r = app_tpp.apply(func=log_visit_record, args=(vr_uri, vr_data), kwds=apply_data)
r = app_tpp.apply_async(func=log_visit_record, args=(vr_uri, vr_data), kwds=apply_data)
print('teardown request')
def row2dict(row):
row_json = {}
for col_name in row:
col_value = row[col_name]
if isinstance(col_value, datetime):
row_json[col_name] = col_value.strftime('%Y-%m-%d %H:%M:%S.%f')
else:
row_json[col_name] = col_value
return row_json
def login_required(func):
@wraps(func)
def decorated_function(*args, **kwargs):
not_in_g = not hasattr(g, 'user') or g.user is None
not_in_s = not 'user' in session or session['user'] is None
if not_in_g and not_in_s:
if 'confirm_route' in current_app.config:
_route = current_app.config['confirm_route']
else:
_route = current_app.config['login_route']
return redirect(url_for(_route, next=request.url))
return func(*args, **kwargs)
return decorated_function
def admin_required(func):
@wraps(func)
def decorated_function(*args, **kwargs):
in_g = hasattr(g, 'user') and not getattr(g, 'user') is None
in_s = 'user' in session and not session['user'] is None
if in_g or in_s:
g_admin = in_g and getattr(g, 'user').is_admin
s_admin = in_s and 'is_admin' in session['user'] and bool(session['user']['is_admin'])
if g_admin or s_admin:
return func(*args, **kwargs)
else:
return abort(403)
else:
if 'confirm_route' in current_app.config:
_route = current_app.config['confirm_route']
else:
_route = current_app.config['login_route']
return redirect(url_for(_route, next=request.url))
return decorated_function
@app.route(r'/<regex("(favicon\.ico)|(robots\.txt)"):_file>')
def favicon(_file):
_file = 'asset/' + _file
asset_file = os.path.join(app.static_folder, _file)
if os.path.exists(asset_file):
return app.send_static_file(_file)
else:
return make_response('')
@app.route(r'/about<regex("[\/]?"):_suffix>')
def view_about(_suffix=None):
return render_template('pages/about.html')
@app.route(r'/copyright<regex("[\/]?"):_suffix>')
def view_copyright(_suffix=None):
return render_template('pages/copyright.html')
@app.route(r'/message<regex("[\/]?"):_suffix>')
def view_message(_suffix=None):
return render_template('pages/message.html')
@app.route(r'/edit<regex("[\/]?"):_suffix>')
def view_edit(_suffix=None):
global categories
global app_db
blog_id = request.values.get('id', None)
tpl_params = dict(categories=categories)
if not blog_id is None:
is_found = False
if blog_id.isdigit():
blogs = app_db['blogs']
blog_item = blogs.find_one(id=int(blog_id))
if isinstance(blog_item, collections.OrderedDict):
blog_item = row2dict(blog_item)
tpl_params['blog_item'] = blog_item
is_found = True
if not is_found:
abort(404)
return render_template('pages/edit.html', **tpl_params)
@app.route(r'/<regex("[\/]?"):_suffix>')
def view_index(_suffix=None):
global app_db
global categories
blogs = app_db['blogs']
count = blogs.count()
articles = blogs.find(_offset=0, _limit=10, order_by='-create_time')
data = []
for row in articles:
data.append(row2dict(row))
if bool(data):
print(data[0].keys())
return render_template('pages/index.html', blog_list=data, categories=categories)
@app.route(r'/detail/<int:blog_id>')
def view_detail(blog_id=None):
global app_db
blogs = app_db['blogs']
blog_item = blogs.find_one(id=int(blog_id))
if isinstance(blog_item, collections.OrderedDict):
blog_item = row2dict(blog_item)
return render_template('pages/detail.html', blog_item=blog_item)
else:
return abort(404)
@app.route(r'/save<regex("[\/]?"):_suffix>', methods=['POST'])
def ajax_save(_suffix=None):
global app_db
global tz
title = request.values.get('title', None)
markdown = request.values.get('markdown', None)
sketch = request.values.get('sketch', None)
if not bool(sketch):
sketch = markdown[:150]
html = request.values.get('html', None)
category = request.values.get('category', None)
tags = request.values.get('tags', None)
blogs = app_db['blogs']
blog_id = request.values.get('id', None)
affect = 0
blog_data = dict(
title=title,
markdown=markdown,
sketch=sketch,
html=html,
category=category,
tags=tags,
create_time=datetime.now(tz)
)
if not blog_id is None:
is_found = False
if blog_id.isdigit():
blog_item = blogs.find_one(id=int(blog_id))
if isinstance(blog_item, collections.OrderedDict):
blog_item.update(blog_data)
affect = blogs.update(blog_item, ['id'])
is_found = True
if not is_found:
abort(404)
else:
affect = blogs.insert(blog_data)
if affect > 0:
ret = {
'error': 0,
'msg': 'sucess'
}
else:
ret = {
'error': 1,
'msg': 'server error'
}
return jsonify(ret)
@app.route(r'/list<regex("[\/]?"):_suffix>', methods=['GET', 'POST'])
def ajax_list(_suffix=None):
global app_db
blogs = app_db['blogs']
count = blogs.count()
articles = blogs.find(_offset=0, _limit=10, order_by='-create_time')
data = []
for row in articles:
data.append(row2dict(row))
return jsonify({
'error': 0,
'msg': 'success',
'data': {
'count': count,
'rows': data
}
})
@app.route(r'/tags<regex("[\/]?"):_suffix>', methods=['GET', 'POST'])
def ajax_tags(_suffix=None):
global app_db
tb_tags = app_db['tags']
count = tb_tags.count()
tag_list = tb_tags.find()
data = []
for row in tag_list:
data.append(row2dict(row))
return jsonify({
'error': 0,
'msg': 'success',
'data': {
'count': count,
'rows': data
}
})
@app.route(r'/ajax/log<regex("[\/]?"):_suffix>', methods=['GET', 'POST'])
def ajax_log(_suffix=None):
job_id = request.values.get('job_id', None)
ret = {
'error': 1,
'msg': '缺少参数'
}
return json.dumps(ret, ensure_ascii=False)
categories = [
{
'name': 'learn-study',
'text': '学习&研究'
},
{
'name': '',
'text': ''
},
{
'name': 'share',
'text': '分享'
},
{
'name': 'memo',
'text': '备忘'
}
]
def test():
app = current_app._get_current_object()
with app.app_context():
print('current_app context test')
if __name__ == '__main__':
if sys.platform == 'win32' or os.name == 'nt':
mp.freeze_support()
log_port = 10909
log_process = mp.Process(
name='log_process',
target=print_log_server,
args=(),
kwargs={
'port': log_port
}
)
log_process.daemon = True
try:
log_process.start()
# 实例化线程池需要在 '__main__' 里面
app.tpp = ThreadPool(processes=cpu_count)
tp_lock = Lock()
debug = app.debug
cfg = {
'host': '0.0.0.0',
'port': 5000
}
if not debug:
# doc: https://docs.pylonsproject.org/projects/waitress/en/latest/#usage
from waitress import serve
serve(app, **cfg)
else:
print('visit by [http://{0}:{1}]'.format(cfg['host'], cfg['port']))
cfg.update({
'debug': debug,
'use_reloader': True,
'threaded': True
})
cfg['extra_files'] = [app.static_folder, app.template_folder]
app.jinja_env.auto_reload = True
app.config['TEMPLATES_AUTO_RELOAD'] = True
app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0
app.run(**cfg)
except (KeyboardInterrupt, SystemExit):
pass
finally:
# log_process.terminate()
log_process.join()
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Python
1
https://gitee.com/gsw945/site-clumsy.git
git@gitee.com:gsw945/site-clumsy.git
gsw945
site-clumsy
site-clumsy
master

Search