Automated update of Base Application package.

This commit is contained in:
bot 2024-12-03 13:19:34 +00:00
parent 6f1d1262e9
commit da6ba57b48
11 changed files with 142 additions and 128 deletions

Binary file not shown.

BIN
dist/app-1.0.0.tar.gz vendored

Binary file not shown.

View File

@ -1,9 +1,9 @@
import logging import logging
logging.basicConfig( logging.basicConfig(
level=logging.DEBUG, level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s', format="%(asctime)s - %(levelname)s - %(message)s",
datefmt='%Y-%m-%d %H:%M:%S' datefmt="%Y-%m-%d %H:%M:%S",
) )
log = logging.getLogger(__name__) log = logging.getLogger(__name__)

View File

@ -1,13 +1,11 @@
from aiohttp import web
from .app import create_app
from .args import parse_args from .args import parse_args
from .server import serve from .server import serve
def main(): def main():
args = parse_args() args = parse_args()
serve(args.host, args.port) serve(args.host, args.port)
if __name__ == '__main__': if __name__ == "__main__":
main() main()

View File

@ -1,29 +1,41 @@
from aiohttp import web import json
import time import time
from . import log
import json
import uuid import uuid
import dataset import dataset
from aiohttp import web
from . import log
def get_timestamp(): def get_timestamp():
from datetime import datetime from datetime import datetime
now = datetime.now() now = datetime.now()
formatted_datetime = now.strftime("%Y-%m-%d %H:%M:%S") formatted_datetime = now.strftime("%Y-%m-%d %H:%M:%S")
return formatted_datetime return formatted_datetime
class BaseApplication(web.Application): class BaseApplication(web.Application):
def __init__(self, username = None, password=None, cookie_name=None,session=None, *args, **kwargs): def __init__(
self,
username=None,
password=None,
cookie_name=None,
session=None,
*args,
**kwargs,
):
self.cookie_name = cookie_name or str(uuid.uuid4()) self.cookie_name = cookie_name or str(uuid.uuid4())
self.username = username self.username = username
self.password = password self.password = password
self.session = session or {} self.session = session or {}
middlewares = kwargs.pop("middlewares",[]) middlewares = kwargs.pop("middlewares", [])
middlewares.append(self.request_middleware) middlewares.append(self.request_middleware)
middlewares.append(self.base64_auth_middleware) middlewares.append(self.base64_auth_middleware)
middlewares.append(self.session_middleware) middlewares.append(self.session_middleware)
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
async def authenticate(self, username, password): async def authenticate(self, username, password):
return self.username == username and self.password == password return self.username == username and self.password == password
@ -37,58 +49,60 @@ class BaseApplication(web.Application):
return web.Response( return web.Response(
status=401, status=401,
text="Unauthorized", text="Unauthorized",
headers={"WWW-Authenticate": 'Basic realm="Restricted"'} headers={"WWW-Authenticate": 'Basic realm="Restricted"'},
) )
try: try:
encoded_credentials = auth_header.split(" ", 1)[1] encoded_credentials = auth_header.split(" ", 1)[1]
decoded_credentials = base64.b64decode(encoded_credentials).decode("utf-8") decoded_credentials = base64.b64decode(encoded_credentials).decode("utf-8")
username, password = decoded_credentials.split(":", 1) username, password = decoded_credentials.split(":", 1)
except (ValueError, base64.binascii.Error): except (ValueError, base64.binascii.Error):
return web.Response(status=400, text="Invalid Authorization Header") return web.Response(status=400, text="Invalid Authorization Header")
if not await self.authenticate(username, password): if not await self.authenticate(username, password):
return web.Response( return web.Response(
status=401, status=401,
text="Invalid Credentials", text="Invalid Credentials",
headers={"WWW-Authenticate": 'Basic realm="Restricted"'} headers={"WWW-Authenticate": 'Basic realm="Restricted"'},
) )
return await handler(request) return await handler(request)
@web.middleware @web.middleware
async def request_middleware(self, request, handler): async def request_middleware(self, request, handler):
time_start = time.time() time_start = time.time()
created = get_timestamp() created = get_timestamp()
request = await handler(request) request = await handler(request)
time_end = time.time() time_end = time.time()
await self.insert("http_access",dict( await self.insert(
created=created, "http_access",
path=request.path, {
duration=time_end - time_start, "created": created,
)) "path": request.path,
"duration": time_end - time_start,
},
)
return request return request
@web.middleware @web.middleware
async def session_middleware(self,request, handler): async def session_middleware(self, request, handler):
# Process the request and get the response # Process the request and get the response
cookies = request.cookies cookies = request.cookies
session_id = cookies.get(self.cookie_name, None) session_id = cookies.get(self.cookie_name, None)
setattr(request,"session", self.session.get(session_id,{})) setattr(request, "session", self.session.get(session_id, {}))
response = await handler(request) response = await handler(request)
if not session_id: if not session_id:
session_id = str(uuid.uuid4()) session_id = str(uuid.uuid4())
response.set_cookie( response.set_cookie(self.cookie_name, session_id, max_age=3600, httponly=True)
self.cookie_name,
session_id,
max_age=3600,
httponly=True
)
return response return response
class WebDbApplication(BaseApplication): class WebDbApplication(BaseApplication):
def __init__(self, db=None, db_web=False,db_path="sqlite:///:memory:",*args, **kwargs): def __init__(
self, db=None, db_web=False, db_path="sqlite:///:memory:", *args, **kwargs
):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.db_web = db_web self.db_web = db_web
self.db_path = db_path self.db_path = db_path
@ -103,53 +117,57 @@ class WebDbApplication(BaseApplication):
self.router.add_post("/delete", self.delete_handler) self.router.add_post("/delete", self.delete_handler)
async def insert_handler(self, request): async def insert_handler(self, request):
obj = await request.json() await request.json()
response = await self.insert(request.get("table"), request.get("data")) response = await self.insert(request.get("table"), request.get("data"))
return web.json_response(response) return web.json_response(response)
async def update_handler(self, request): async def update_handler(self, request):
obj = await request.json() await request.json()
response = await self.update(request.get('table'), request.get('data'), request.get('where',{})) response = await self.update(
request.get("table"), request.get("data"), request.get("where", {})
)
return web.json_response(response) return web.json_response(response)
async def upsert_handler(self, request): async def upsert_handler(self, request):
obj = await request.json() await request.json()
response = await self.upsert(request.get('table'), request.get('data'), request.get('keys',[])) response = await self.upsert(
request.get("table"), request.get("data"), request.get("keys", [])
)
return web.json_response(response) return web.json_response(response)
async def find_handler(self, request): async def find_handler(self, request):
obj = await request.json() await request.json()
response = await self.find(request.get('table'), requesst.get('where',{})) response = await self.find(request.get("table"), requesst.get("where", {}))
return web.json_response(response) return web.json_response(response)
async def find_one_handler(self, request): async def find_one_handler(self, request):
obj = await request.json() await request.json()
response = await self.find_one(request.get('table'), requesst.get('where',{})) response = await self.find_one(request.get("table"), requesst.get("where", {}))
return web.json_response(response) return web.json_response(response)
async def delete_handler(self, request): async def delete_handler(self, request):
obj = await request.json() await request.json()
response = await self.delete(request.get('table'), requesst.get('where',{})) response = await self.delete(request.get("table"), requesst.get("where", {}))
return web.json_response(response) return web.json_response(response)
async def set(self, key, value): async def set(self, key, value):
value = json.dumps(value, default=str) value = json.dumps(value, default=str)
self.db['kv'].upsert(dict(key=key,value=value),['key']) self.db["kv"].upsert({"key": key, "value": value}, ["key"])
async def get(self, key, default=None): async def get(self, key, default=None):
record = self.db['kv'].find_one(key=key) record = self.db["kv"].find_one(key=key)
if record: if record:
return json.loads(record.get('value','null')) return json.loads(record.get("value", "null"))
return default return default
async def insert(self, table_name, data): async def insert(self, table_name, data):
return self.db[table_name].insert(data) return self.db[table_name].insert(data)
async def update(self, table_name, data, where): async def update(self, table_name, data, where):
return self.db[table_name].update(data,where) return self.db[table_name].update(data, where)
async def upsert(self, table_name, data, keys): async def upsert(self, table_name, data, keys):
return self.db[table_name].upsert(data,keys or []) return self.db[table_name].upsert(data, keys or [])
async def find(self, table_name, filters): async def find(self, table_name, filters):
if not filters: if not filters:
@ -162,17 +180,15 @@ class WebDbApplication(BaseApplication):
try: try:
return dict(self.db[table_name].find_one(**filters)) return dict(self.db[table_name].find_one(**filters))
except ValueError: except ValueError:
return None return None
async def delete(self, table_name, where): async def delete(self, table_name, where):
return self.db[table_name].delete(**where) return self.db[table_name].delete(**where)
class Application(WebDbApplication): class Application(WebDbApplication):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.on_startup.append(self.on_startup_task) self.on_startup.append(self.on_startup_task)
self.router.add_get("/", self.index_handler) self.router.add_get("/", self.index_handler)
@ -189,19 +205,22 @@ class Application(WebDbApplication):
self.running_since = get_timestamp() self.running_since = get_timestamp()
async def inc_request_count(self): async def inc_request_count(self):
request_count = await self.get("root_request_count",0) request_count = await self.get("root_request_count", 0)
request_count += 1 request_count += 1
await self.set("root_request_count", request_count) await self.set("root_request_count", request_count)
return request_count return request_count
async def index_handler(self,request): async def index_handler(self, request):
return web.json_response(dict( return web.json_response(
request_count=await self.inc_request_count(), {
timestamp=get_timestamp(), "request_count": await self.inc_request_count(),
uptime=self.uptime, "timestamp": get_timestamp(),
running_since=self.running_since "uptime": self.uptime,
),content_type="application/json") "running_since": self.running_since,
},
content_type="application/json",
)
def create_app(*args, **kwargs): def create_app(*args, **kwargs):

View File

@ -1,36 +1,31 @@
import argparse import argparse
def parse_args(): def parse_args():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(description="Async web service")
description="Async web service"
)
parser.add_argument( parser.add_argument(
'--host', "--host",
type=str, type=str,
required=False, required=False,
default="0.0.0.0", default="0.0.0.0",
help='Host to serve on. Default: 0.0.0.0.' help="Host to serve on. Default: 0.0.0.0.",
) )
parser.add_argument( parser.add_argument(
'--port', "--port",
type=int, type=int,
required=False, required=False,
default=8888, default=8888,
help='Port to serve on Default: 8888.' help="Port to serve on Default: 8888.",
) )
parser.add_argument( parser.add_argument(
'--url', "--url",
type=str, type=str,
default="http://localhost:8888", default="http://localhost:8888",
required=False, required=False,
help='Base URL.' help="Base URL.",
) )
return parser.parse_args() return parser.parse_args()

View File

@ -1,23 +1,24 @@
import asyncio import asyncio
import time
from aiohttp import ClientSession from aiohttp import ClientSession
from . import log
from .args import parse_args from .args import parse_args
import time
from . import log
async def cli_client(url): async def cli_client(url):
while True: while True:
sentence = input("> ") sentence = input("> ")
async with ClientSession() as session: async with ClientSession() as session:
async with session.post("http://localhost:8080",json=sentence) as response: async with session.post("http://localhost:8080", json=sentence) as response:
try: try:
print(await response.json()) print(await response.json())
except Exception as ex: except Exception as ex:
print(ex) print(ex)
print(await response.text()) print(await response.text())
async def bench(url): async def bench(url):
index = 0 index = 0
while True: while True:
@ -28,13 +29,14 @@ async def bench(url):
async with ClientSession() as session: async with ClientSession() as session:
async with session.get(url) as response: async with session.get(url) as response:
print(await response.text()) print(await response.text())
#print(await response.json()) # print(await response.json())
time_end = time.time() time_end = time.time()
print("Request {}. Duration: {}".format(index,time_end-time_start)) print(f"Request {index}. Duration: {time_end - time_start}")
except Exception as ex: except Exception as ex:
log.exception(ex) log.exception(ex)
await asyncio.sleep(1) await asyncio.sleep(1)
def cli_bench(): def cli_bench():
args = parse_args() args = parse_args()
asyncio.run(bench(args.url)) asyncio.run(bench(args.url))
@ -44,9 +46,6 @@ def main():
args = parse_args() args = parse_args()
asyncio.run(cli_client(args.url)) asyncio.run(cli_client(args.url))
if __name__ == '__main__':
if __name__ == "__main__":
main() main()

View File

@ -1,17 +1,18 @@
#!/usr/bin/python3 #!/usr/bin/python3
import sys
import shutil import shutil
import sys
from readchar import readkey from readchar import readkey
def text_editor(init='', prompt=''): def text_editor(init="", prompt=""):
''' """
Allow user to edit a line of text complete with support for line wraps Allow user to edit a line of text complete with support for line wraps
and a cursor | you can move back and forth with the arrow keys. and a cursor | you can move back and forth with the arrow keys.
init = initial text supplied to edit init = initial text supplied to edit
prompt = Decoration presented before the text (not editable and not returned) prompt = Decoration presented before the text (not editable and not returned)
''' """
term_width = shutil.get_terminal_size()[0] term_width = shutil.get_terminal_size()[0]
ptr = len(init) ptr = len(init)
@ -25,26 +26,24 @@ def text_editor(init='', prompt=''):
copy = prompt + text.copy() copy = prompt + text.copy()
if ptr < len(text): if ptr < len(text):
copy.insert(ptr + len(prompt), '|') copy.insert(ptr + len(prompt), "|")
# Line wraps support: # Line wraps support:
if len(copy) > term_width: if len(copy) > term_width:
cut = len(copy) + 3 - term_width cut = len(copy) + 3 - term_width
if ptr > len(copy) / 2: if ptr > len(copy) / 2:
copy = ['<'] * 3 + copy[cut:] copy = ["<"] * 3 + copy[cut:]
else: else:
copy = copy[:-cut] + ['>'] * 3 copy = copy[:-cut] + [">"] * 3
# Display current line # Display current line
print('\r' * term_width + ''.join(copy), end=' ' * (term_width - len(copy))) print("\r" * term_width + "".join(copy), end=" " * (term_width - len(copy)))
# Read new character into c # Read new character into c
if c in (53, 54): if c in (53, 54):
# Page up/down bug # Page up/down bug
c = readkey() c = readkey()
if c == '~': if c == "~":
continue continue
else: else:
c = readkey() c = readkey()
@ -52,17 +51,17 @@ def text_editor(init='', prompt=''):
if len(c) > 1: if len(c) > 1:
# Control Character # Control Character
c = ord(c[-1]) c = ord(c[-1])
if c == 68: # Left if c == 68: # Left
ptr -= 1 ptr -= 1
elif c == 67: # Right elif c == 67: # Right
ptr += 1 ptr += 1
elif c == 53: # PgDn elif c == 53: # PgDn
ptr -= term_width // 2 ptr -= term_width // 2
elif c == 54: # PgUp elif c == 54: # PgUp
ptr += term_width // 2 ptr += term_width // 2
elif c == 70: # End elif c == 70: # End
ptr = len(text) ptr = len(text)
elif c == 72: # Home elif c == 72: # Home
ptr = 0 ptr = 0
else: else:
print("\nUnknown control character:", c) print("\nUnknown control character:", c)
@ -77,17 +76,18 @@ def text_editor(init='', prompt=''):
num = ord(c) num = ord(c)
if num in (13, 10): # Enter if num in (13, 10): # Enter
print() print()
return ''.join(text) return "".join(text)
elif num == 127: # Backspace elif num == 127: # Backspace
if text: if text:
text.pop(ptr - 1) text.pop(ptr - 1)
ptr -= 1 ptr -= 1
elif num == 3: # Ctrl-C elif num == 3: # Ctrl-C
sys.exit(1) sys.exit(1)
else: else:
# Insert normal character into text. # Insert normal character into text.
text.insert(ptr, c) text.insert(ptr, c)
ptr += 1 ptr += 1
if __name__ == "__main__": if __name__ == "__main__":
print("Result =", text_editor('Edit this text', prompt="Prompt: ")) print("Result =", text_editor("Edit this text", prompt="Prompt: "))

View File

@ -1,4 +1,4 @@
import code import code
def repl(**kwargs): def repl(**kwargs):
@ -8,6 +8,7 @@ def repl(**kwargs):
variables.update(kwargs) variables.update(kwargs)
code.interact(local=variables) code.interact(local=variables)
if __name__ == "__main__": if __name__ == "__main__":
repl() repl()

View File

@ -1,14 +1,17 @@
from aiohttp import web import time
from .app import create_app
from . import log
import time
def serve(host="0.0.0.0",port=8888): from aiohttp import web
from . import log
from .app import create_app
def serve(host="0.0.0.0", port=8888):
app = create_app() app = create_app()
log.info("Serving on {}:{}".format(host,port)) log.info(f"Serving on {host}:{port}")
while True: while True:
try: try:
web.run_app(app,host=host,port=port) web.run_app(app, host=host, port=port)
except KeyboardInterrupt: except KeyboardInterrupt:
break break
except Exception as ex: except Exception as ex:

View File

@ -1,20 +1,19 @@
from .app import WebDbApplication
import unittest import unittest
import asyncio
from .app import WebDbApplication
class WebDbApplicationTestCase(unittest.IsolatedAsyncioTestCase): class WebDbApplicationTestCase(unittest.IsolatedAsyncioTestCase):
def setUp(self): def setUp(self):
self.db = WebDbApplication() self.db = WebDbApplication()
async def test_insert(self): async def test_insert(self):
self.assertEqual(await self.db.insert("test",dict(test=True)), 1) self.assertEqual(await self.db.insert("test", {"test": True}), 1)
self.assertEqual(len(await self.db.find("test",dict(test=True, id=1))), 1) self.assertEqual(len(await self.db.find("test", {"test": True, "id": 1})), 1)
async def test_find(self): async def test_find(self):
print(await self.db.find("test",None)) print(await self.db.find("test", None))
# self.assertEqual(len(await self.db.find("test",dict(test=True, id=1))), 1) # self.assertEqual(len(await self.db.find("test",dict(test=True, id=1))), 1)