Fetch the repository succeeded.
# -*- 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>⇢↠ <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()
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。