Migrating the project to an asynchronous model

This commit is contained in:
Bigsk 2024-09-26 18:45:19 +08:00
parent eeff5c307c
commit 463b2bcd8c
5 changed files with 228 additions and 427 deletions

View File

@ -1,14 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Ghink Universe - 404</title>
<link rel="icon" href="https://cdn.ghink.net/image/ghink/favicon.ico" type="image/x-icon">
<link rel="icon" href="https://cdn.gh.ink/image/ghink/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="https://cdn.gh.ink/assembly/aplayer/1.10.0/APlayer.min.css">
<script src="https://cdn.gh.ink/js/vue/2.6.14/vue.min.js"></script>
<script src="https://cdn.gh.ink/js/axios/1.1.3/axios.min.js"></script>
<script src="https://cdn.gh.ink/site/public/js/msg.js"></script>
<style>
body {
background-color: #2F3242;
}
svg {
.svg {
position: absolute;
top: 50%;
left: 50%;
@ -21,7 +27,7 @@
position: absolute;
top: 50%;
left: 50%;
margin-top: -100px;
margin-top: -200px;
margin-left: 50px;
color: #FFF;
font-family: Roboto;
@ -32,6 +38,10 @@
line-height: 46px;
margin-bottom: 40px;
}
.music {
margin-top: 50px;
color: #000;
}
.buttons-con .action-link-wrap {
margin-top: 40px;
}
@ -74,8 +84,7 @@
}
}
@media (max-width: 450px) {
svg {
position: absolute;
.svg {
top: 50%;
left: 50%;
margin-top: -250px;
@ -88,11 +97,15 @@
margin-left: -190px;
text-align: center;
}
.music {
margin-top: 50px;
color: #000;
}
}
</style>
</head>
<body>
<svg width="380px" height="500px" viewBox="0 0 837 1045" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns">
<svg width="380px" height="500px" viewBox="0 0 837 1045" version="1.1" xmlns="https://www.w3.org/2000/svg" xmlns:xlink="https://www.w3.org/1999/xlink" xmlns:sketch="https://www.bohemiancoding.com/sketch/ns" class="svg">
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" sketch:type="MSPage">
<path d="M353,9 L626.664028,170 L626.664028,487 L353,642 L79.3359724,487 L79.3359724,170 L353,9 Z" id="Polygon-1" stroke="#007FB2" stroke-width="6" sketch:type="MSShapeGroup"></path>
<path d="M78.5,529 L147,569.186414 L147,648.311216 L78.5,687 L10,648.311216 L10,569.186414 L78.5,529 Z" id="Polygon-2" stroke="#EF4A5B" stroke-width="6" sketch:type="MSShapeGroup"></path>
@ -103,13 +116,40 @@
</svg>
<div class="message-box">
<h1>404</h1>
<p>Page not found 页面找不到了</p>
<p>
<strong>Page not found 页面找不到了</strong>
</p>
<div class="buttons-con">
<div class="action-link-wrap">
<a onclick="history.back(-1)" class="link-button link-back-button">Go Back 返回</a>
<a href="https://www.ghink.net" class="link-button">Go Home 返回主页</a>
</div>
<div id="aplayer" class="music"></div>
</div>
</div>
<script src="https://cdn.gh.ink/assembly/aplayer/1.10.0/APlayer.min.js"></script>
<script>
new Vue({
el: '#app',
mounted () {
axios
.get('https://api.gh.ink/404music')
.then(function (response) {
const ap = new APlayer({
container: document.getElementById('aplayer'),
autoplay: false,
loop: 'all',
listFolded: true,
theme: '#5A5C6C',
order: "random",
audio: response.data.content
});
})
.catch(function (error) {
console.log(error);
});
}
})
</script>
</body>
</html>

View File

@ -1,3 +1,9 @@
# short_link
# Short Link
Ghink Universe Short Link Service Source Code
## Usage
1. Install all requirements
2. Configure like example config
3. Run it!

File diff suppressed because one or more lines are too long

170
main.py
View File

@ -1,6 +1,11 @@
import time, random, json, threading
import pymysql
from flask import Flask, request, redirect
import time
import random
import json
from quart import Quart, request, redirect
import aiomysql
import aiofiles
with open("config.json", "r") as fb:
config = json.loads(fb.read())
@ -9,13 +14,8 @@ with open("config.json", "r") as fb:
LISTEN = config["LISTEN"]
DEBUG = config["DEBUG"]
app = Flask("Ghink Short Link Service")
db = pymysql.connect(
host=DB["host"],
user=DB["user"],
password=DB["password"],
database=DB["database"]
)
app = Quart("Ghink Short Link Service")
db_pool = None
field_map = {
'A': 0, 'a': 1, 'B': 2, 'b': 3,
@ -33,63 +33,67 @@ field_map = {
'v': 48, 'W': 49, 'w': 50, 'X': 51,
'x': 52, '6': 53, 'Y': 54, 'y': 55,
'Z': 56, 'z': 57, '7': 58, '8': 59,
'9': 60, '0': 61}
'9': 60, '0': 61
}
@app.route("/", methods=["GET"])
def index():
with open("index.html", "r", encoding="utf-8") as fb:
return fb.read()
@app.route("/<string:link_id>", methods=["GET"])
def route(link_id: str):
global db
for char in link_id:
if char not in tuple(field_map.keys()):
return redirect("https://www.ghink.net")
link_id_converted = 0
for i in range(len(link_id)):
link_id_converted += field_map[link_id[::-1][i]] * 62 ** i
try:
db.ping()
except pymysql.err.InterfaceError:
db = pymysql.connect(
async def init_db():
global db_pool
db_pool = await aiomysql.create_pool(
host=DB["host"],
user=DB["user"],
password=DB["password"],
database=DB["database"]
db=DB["database"],
autocommit=True
)
cursor = db.cursor()
cursor.execute('SELECT link, validity FROM links WHERE id=%s', link_id_converted)
db.commit()
link = cursor.fetchone()
@app.before_serving
async def startup():
await init_db()
@app.after_serving
async def shutdown():
db_pool.close()
await db_pool.wait_closed()
@app.route("/", methods=["GET"])
async def index():
return redirect("https://k76u22n4gd.apifox.cn")
@app.route("/<string:link_id>", methods=["GET"])
async def route(link_id: str):
for char in link_id:
if char not in field_map:
return redirect("https://www.ghink.net")
link_id_converted = sum(field_map[link_id[::-1][i]] * 62 ** i for i in range(len(link_id)))
async with db_pool.acquire() as conn:
async with conn.cursor() as cursor:
await cursor.execute('SELECT link, validity FROM links WHERE id=%s', (link_id_converted,))
link = await cursor.fetchone()
if link is None or link[0] is None:
with open("404.html", "r", encoding="utf-8") as fb:
return fb.read(), 404
async with aiofiles.open("404.html", "r", encoding="utf-8") as fb:
return await fb.read(), 404
if link[1] is not None and link[1] < time.time():
remove_thread = threading.Thread(target=remove_link, args=(link_id_converted,))
remove_thread.start()
with open("404.html", "r", encoding="utf-8") as fb:
return fb.read(), 404
await remove_link(link_id_converted)
async with aiofiles.open("404.html", "r", encoding="utf-8") as fb:
return await fb.read(), 404
return redirect(link[0])
@app.route("/", methods=["POST"])
def add():
global db
key = request.form.get("key")
link = request.form.get("link")
validity = request.form.get("validity")
# Judge whether fields are empty
if key == "" or link == "":
async def add():
form = await request.form # Await the form to get the data
key = form.get("key") # Access the key
link = form.get("link") # Access the link
validity = form.get("validity") # Access the validity
if not key or not link:
return json.dumps({"ok": False, "message": "bad field(s)", "id": ""})
# No access
if key not in KEYS:
return json.dumps({"ok": False, "message": "forbidden", "id": ""})
# Check validity
if validity:
if validity.isdecimal() and int(validity) > time.time():
validity = int(validity)
@ -98,37 +102,25 @@ def add():
else:
validity = None
# Random
while True:
link_id_random = ''.join(random.sample(tuple(field_map.keys()), 6))
link_id_converted = 0
for i in range(len(link_id_random)):
link_id_converted += field_map[link_id_random[::-1][i]] * 62 ** i
# Get Cursor
try:
db.ping()
except pymysql.err.InterfaceError:
db = pymysql.connect(
host=DB["host"],
user=DB["user"],
password=DB["password"],
database=DB["database"]
)
cursor = db.cursor()
cursor.execute('SELECT link FROM links WHERE id=%s', link_id_converted)
db.commit()
link_selected = cursor.fetchone()
link_id_random = ''.join(random.sample(field_map.keys(), 6))
link_id_converted = sum(field_map[link_id_random[::-1][i]] * 62 ** i for i in range(len(link_id_random)))
async with db_pool.acquire() as conn:
async with conn.cursor() as cursor:
await cursor.execute('SELECT link FROM links WHERE id=%s', (link_id_converted,))
link_selected = await cursor.fetchone()
if link_selected is None:
break
# Insert
cursor.execute("INSERT INTO `links` VALUES (%s, %s, %s)", [link_id_converted, link, validity])
db.commit()
async with db_pool.acquire() as conn:
async with conn.cursor() as cursor:
await cursor.execute("INSERT INTO `links` VALUES (%s, %s, %s)", (link_id_converted, link, validity))
return json.dumps({"ok": True, "message": "successful", "id": link_id_random})
@app.route("/", methods=["PATCH"])
def reload():
async def reload():
global config, DB, KEYS, LISTEN, DEBUG
with open("config.json", "r") as fb:
@ -140,24 +132,10 @@ def reload():
return json.dumps({"ok": True, "message": "successful"})
def remove_link(id):
global db
# Get Cursor
try:
db.ping()
except pymysql.err.InterfaceError:
db = pymysql.connect(
host=DB["host"],
user=DB["user"],
password=DB["password"],
database=DB["database"]
)
cursor = db.cursor()
cursor.execute('DELETE FROM links WHERE id=%s', id)
db.commit()
async def remove_link(id):
async with db_pool.acquire() as conn:
async with conn.cursor() as cursor:
await cursor.execute('DELETE FROM links WHERE id=%s', (id,))
if __name__ == "__main__":
app.run(LISTEN[0], LISTEN[1], DEBUG)
db.close()
app.run(host=LISTEN[0], port=LISTEN[1], debug=DEBUG)

3
requirements.txt Normal file
View File

@ -0,0 +1,3 @@
aiomysql
aiofiles
quart