From 85fa88dcb0d9132a85b6d766e236e348ee4856db Mon Sep 17 00:00:00 2001 From: th3r00t Date: Wed, 2 Sep 2020 17:42:08 -0400 Subject: [PATCH] On demand import functionality, held together with ductape and bubblegum. --- pyShelf.py | 2 +- requirements.txt | 1 + src/backend/lib/config.py | 12 ++-- src/backend/lib/pyShelf.py | 31 +++++++--- src/interface/static/js/pyshelf_ux.js | 87 +++++++-------------------- src/interface/views.py | 57 ++++++++++++------ 6 files changed, 91 insertions(+), 99 deletions(-) diff --git a/pyShelf.py b/pyShelf.py index 7f5d7bd..f9f034b 100755 --- a/pyShelf.py +++ b/pyShelf.py @@ -4,7 +4,6 @@ import sys from pathlib import Path import websockets -from loguru import logger from src.backend.lib.config import Config from src.backend.pyShelf_MakeCollections import MakeCollections @@ -26,6 +25,7 @@ async def runImport(): async def socketio(websocket, path): async for message in websocket: + config.logger.info("Message Processing") if message == "ping": config.logger.info("<< Ping") tx = pong(message) diff --git a/requirements.txt b/requirements.txt index 2cdef29..987a1bb 100755 --- a/requirements.txt +++ b/requirements.txt @@ -23,3 +23,4 @@ jsonpickle django-widget-tweaks loguru ptvsd +pudb \ No newline at end of file diff --git a/src/backend/lib/config.py b/src/backend/lib/config.py index 2bacdfd..fcb590b 100755 --- a/src/backend/lib/config.py +++ b/src/backend/lib/config.py @@ -19,7 +19,8 @@ class Config: self._fp = "config.json" self._cp = pathlib.Path.joinpath(root, self._fp) self._data = self.open_file() - self.logger = self.get_logger() + try: self.logger + except AttributeError: self.logger = self.get_logger() self.book_path = self._data["BOOKPATH"] self.TITLE = self._data["TITLE"] self.VERSION = self._data["VERSION"] @@ -30,11 +31,8 @@ class Config: self.password = self._data["PASSWORD"] self.db_host = self._data["DB_HOST"] self.db_port = self._data["DB_PORT"] - self.file_array = [ - self.book_shelf, - ] + self.file_array = [self.book_shelf] self.auto_scan = True - self.allowed_hosts = self._data["ALLOWED_HOSTS"] self.db_user = self._data["USER"] self.db_pass = self._data["PASSWORD"] @@ -42,8 +40,8 @@ class Config: def get_logger(self): _logger = logger - _logger.add(pathlib.PurePath(self.root, 'data','pyShelf_{time}.log'), - rotation="10 MB", enqueue=True, colorize=True) + _logger.add(pathlib.PurePath(self.root, 'data','{time}.log'), + rotation="2 MB", enqueue=True, colorize=True) return _logger def open_file(self): diff --git a/src/backend/lib/pyShelf.py b/src/backend/lib/pyShelf.py index 8a7da21..43d9ef4 100755 --- a/src/backend/lib/pyShelf.py +++ b/src/backend/lib/pyShelf.py @@ -36,15 +36,22 @@ class Server: :TODO: Document this """ - async def __init__(self, root): + def __init__(self, root): self.root = root + self.host = ("127.0.0.1", 1337) self.config = Config(self.root) - self.instance = None - self.serve = await websockets.serve(socketio, "127.0.0.1", 1337) + self.loop = None + self.serve = None async def __aexit__(self, *args, **kwargs): await self.serve.__aexit__(*args, **kwargs) + async def initialize_server(self): + self.config.logger.info("INITIALIZE") + self.serve = await websockets.serve(self.socketio, self.host[0], self.host[1]) + await asyncio.sleep(.01) + self.config.logger.info("Server Initialization Complete") + async def runImport(self): _start_time = time.time() InitFiles(self.config.file_array) @@ -55,21 +62,29 @@ class Server: _total_time = round(time.time() - _start_time) async def socketio(self, websocket, path): + self.config.logger.info("Listener Starting") async for message in websocket: if message == "ping": - config.logger.info("<< Ping") + self.config.logger.info("<< Ping") tx = self.pong() elif message == "importBooks": - config.logger.info("Starting Import") + self.config.logger.info("Starting Import") tx = "Starting Import . . ." await websocket.send(tx) - await runImport() + await asyncio.sleep(0.01) + await self.runImport() + await asyncio.sleep(0.01) tx = "complete" + else: + self.config.logger.info("Unhandled Message Rcvd :: {}".format(message)) await websocket.send(tx) def pong(self): self.config.logger.info(">> Pong") return "pong" - def start(self): - asyncio.get_event_loop().run_until_complete(self.serve) + async def start(self): + self.loop = asyncio.get_running_loop() + self.loop.set_debug(True) + await websockets.serve(self.socketio, self.host[0], self.host[1]) + await asyncio.sleep(1) diff --git a/src/interface/static/js/pyshelf_ux.js b/src/interface/static/js/pyshelf_ux.js index 468281a..c17b1fb 100755 --- a/src/interface/static/js/pyshelf_ux.js +++ b/src/interface/static/js/pyshelf_ux.js @@ -1,3 +1,13 @@ + +async function WebSocketInterface(host) { + let socket = new WebSocket(host) + socket.onopen = function(e) { console.log('Connected') } + socket.onmessage = function (rcvd){ + rx_msg(rcvd.data) + }} +async function rx_msg(rcvd) { console.log('msg :: '+rcvd) } +async function tx_msg(socket, msg) { socket.send(msg) } + $(document).ready(function(){ function customlog(outstream) { /* Gather my variables and output them */ @@ -171,16 +181,9 @@ $(document).ready(function(){ $('#pop_over_0').dialog("open"); }); $(document).on('click', '.logout-btn', function(){window.location.href = '/logout'}); + + //Web Socket Call $(document).on('click', '.import-btn', async function(){ - $.ajax({ - type: "GET", url: "/live", data: {hook: 'import_books'}, - success: function (response) { - }, - error: function (response) { - customlog(["Failure", response]); - } - }); - let connection = await ImportBooks(server); popover.html('
'); let psout = $('#psout') psout.append('
Importing Books
') @@ -192,6 +195,16 @@ $(document).ready(function(){ value: false }); $(".progressbar").append("
") + $.ajax({ + type: "GET", url: "/live", data: {hook: 'import_books'}, + success: async function (response,sock) { + customlog(["Backend Reports websocket server READY"]) + $('.progressbar').progressbar({ value: true }) + }, + error: function (response) { + customlog(["Failure", response.data]); + } + }); }); $('#coll_button').on('click', function(){ var isopen = $('#pop_over_0').dialog("isOpen"); @@ -285,59 +298,3 @@ function resize_search(win_width){ $('.search_string').val("Search"); } } - -function OpenSocket(address) { - return new Promise(resolve => { - const connection = new WebSocket(address); - connection.onopen = function(e){ - console.log('--[ Connection Established ]') - ping(connection) - }; - connection.onmessage = function(rcvd){ - sock_rx(rcvd) - }; - resolve(connection); - }); -} - -function ImportBooks(address) { - return new Promise(resolve => { - const connection = new WebSocket(address); - connection.onopen = function(e){ - sock_tx(connection,'importBooks') - }; - connection.onmessage = function(rcvd){ - sock_rx(rcvd) - }; - resolve(connection); - }); -} - -async function PyshelfServer(address){ - console.log("--[ Starting Connection ]") - return await OpenSocket(address) -} -function sock_rx(rcvd) { - if (rcvd.data == 'pong') { pong(rcvd) } - else if (rcvd.data == 'complete') { - $('.progressbar').progressbar("option", "value", "True"); - $('.import_status').html('Import Complete') - console.log(rcvd.data) - } - else { console.log("<<[rx] :"+rcvd.data) } -} -function sock_tx(connection, msg) { - connection.send(msg); -} -function sock_status(connection) { - let buffered = connection.bufferedAmmount; - let ready = connection.readyState; - return [buffered, ready]; -} -function ping(connection) { - connection.send('ping'); - console.log("[ping]>>"); -} -function pong(rcvd) { - console.log("<<["+rcvd+"]") -} diff --git a/src/interface/views.py b/src/interface/views.py index f58cdcb..6494390 100755 --- a/src/interface/views.py +++ b/src/interface/views.py @@ -7,6 +7,7 @@ import time from base64 import b64decode, b64encode from pathlib import Path +import websockets from backend.lib.config import Config from backend.lib.pyShelf import Server from django.conf import settings @@ -384,7 +385,7 @@ def collections_list(): return list(set(collection_key)) -def live(request, **kwargs): +async def live(request, **kwargs): """ Respond to live requests. Primarily used as a response object for Ajax calls :param GET['hook']: collection_listing, book_details, register @@ -411,33 +412,53 @@ def live(request, **kwargs): return JsonResponse({"data": html}) elif hook == "import_books": - """TODO: Spawn websocket server""" - breakpoint() - ################################################### - # async def responder(socket): # - # await catalogue.import_books(socket=socket) # - # return JsonResponse({"data": None}) # - # pass # - # asyncio.run(responder(None)) # - ################################################### - def test_connection(host): - with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: - s.connect(host) - s.sendall(b"ping") - data = s.recv(1024) - return data + _test_count = 0 + await Server(Path.absolute(Path.cwd().parent)).start() + await asyncio.sleep(1) + + async def test_connection(host, counter): + async with websockets.connect(f'ws://{host[0]}:{host[1]}') as _s: + await _s.send("ping") + data = await _s.recv() + counter = counter + 1 + if data == "pong": + return True + else: + return False + + async def runImport(host): + async with websockets.connect(f'ws://{host[0]}:{host[1]}') as _s: + await _s.send("importBooks") + data = await _s.recv() + if data == "complete": + return JsonResponse({"data": data}) + else: + return False + _host = ("127.0.0.1", 1337) + _test_count = 0 try: - _server_response = test_connection(_host) + if await test_connection(_host, _test_count): + config.logger.info("Connection Successful") + await runImport(_host) + return JsonResponse({"data": "Response sent"}, status=200) except ConnectionRefusedError as e: config.logger.info(e) if e.errno == 111: - request.server = Server(Path.absolute(Path.cwd().parent)).start() + await Server(Path.absolute(Path.cwd().parent)).start() + if await test_connection(_host, _test_count): + return JsonResponse({"data": "Response sent"}, status=200) + elif not await test_connection(_host, _test_count) & _test_count >=4: + await Server(Path.absolute(Path.cwd().parent)).start() + await test_connection(_host, _test_count) + else: + return JsonResponse({"data": "Websocket Failed Testing"}, status=401) else: return JsonResponse(err_txt, status=404) return JsonResponse({"data": "Response sent"}, status=200) + def book_details(book): return { 'title': book.title,