fix(pagination): Fixed socket gevent (#95)
This commit is contained in:
4
app.py
4
app.py
@@ -1,6 +1,6 @@
|
|||||||
# This need to be first
|
# This need to be first
|
||||||
import eventlet
|
import gevent.monkey
|
||||||
eventlet.monkey_patch()
|
gevent.monkey.patch_all()
|
||||||
|
|
||||||
import logging # noqa: E402
|
import logging # noqa: E402
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ from flask_socketio import SocketIO
|
|||||||
|
|
||||||
from .instructions import BrickInstructions
|
from .instructions import BrickInstructions
|
||||||
from .instructions_list import BrickInstructionsList
|
from .instructions_list import BrickInstructionsList
|
||||||
|
from .peeron_instructions import PeeronPage
|
||||||
|
from .peeron_pdf import PeeronPDF
|
||||||
from .set import BrickSet
|
from .set import BrickSet
|
||||||
from .socket_decorator import authenticated_socket, rebrickable_socket
|
from .socket_decorator import authenticated_socket, rebrickable_socket
|
||||||
from .sql import close as sql_close
|
from .sql import close as sql_close
|
||||||
@@ -18,6 +20,7 @@ MESSAGES: Final[dict[str, str]] = {
|
|||||||
'CONNECT': 'connect',
|
'CONNECT': 'connect',
|
||||||
'DISCONNECT': 'disconnect',
|
'DISCONNECT': 'disconnect',
|
||||||
'DOWNLOAD_INSTRUCTIONS': 'download_instructions',
|
'DOWNLOAD_INSTRUCTIONS': 'download_instructions',
|
||||||
|
'DOWNLOAD_PEERON_PAGES': 'download_peeron_pages',
|
||||||
'FAIL': 'fail',
|
'FAIL': 'fail',
|
||||||
'IMPORT_SET': 'import_set',
|
'IMPORT_SET': 'import_set',
|
||||||
'LOAD_SET': 'load_set',
|
'LOAD_SET': 'load_set',
|
||||||
@@ -70,7 +73,7 @@ class BrickSocket(object):
|
|||||||
*args,
|
*args,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
path=app.config['SOCKET_PATH'],
|
path=app.config['SOCKET_PATH'],
|
||||||
async_mode='eventlet',
|
async_mode='gevent',
|
||||||
)
|
)
|
||||||
|
|
||||||
# Store the socket in the app config
|
# Store the socket in the app config
|
||||||
@@ -106,6 +109,56 @@ class BrickSocket(object):
|
|||||||
|
|
||||||
BrickInstructionsList(force=True)
|
BrickInstructionsList(force=True)
|
||||||
|
|
||||||
|
@self.socket.on(MESSAGES['DOWNLOAD_PEERON_PAGES'], namespace=self.namespace) # noqa: E501
|
||||||
|
@authenticated_socket(self)
|
||||||
|
def download_peeron_pages(data: dict[str, Any], /) -> None:
|
||||||
|
logger.debug('Socket: DOWNLOAD_PEERON_PAGES={data} (from: {fr})'.format(
|
||||||
|
data=data,
|
||||||
|
fr=request.sid, # type: ignore
|
||||||
|
))
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Extract data from the request
|
||||||
|
set_number = data.get('set', '')
|
||||||
|
pages_data = data.get('pages', [])
|
||||||
|
|
||||||
|
if not set_number:
|
||||||
|
raise ValueError("Set number is required")
|
||||||
|
|
||||||
|
if not pages_data:
|
||||||
|
raise ValueError("No pages selected")
|
||||||
|
|
||||||
|
# Parse set number
|
||||||
|
if '-' in set_number:
|
||||||
|
parts = set_number.split('-', 1)
|
||||||
|
set_num = parts[0]
|
||||||
|
version_num = parts[1] if len(parts) > 1 else '1'
|
||||||
|
else:
|
||||||
|
set_num = set_number
|
||||||
|
version_num = '1'
|
||||||
|
|
||||||
|
# Convert page data to PeeronPage objects
|
||||||
|
pages = []
|
||||||
|
for page_data in pages_data:
|
||||||
|
page = PeeronPage(
|
||||||
|
page_number=page_data.get('page_number', ''),
|
||||||
|
thumbnail_url=page_data.get('thumbnail_url', ''),
|
||||||
|
image_url=page_data.get('image_url', ''),
|
||||||
|
alt_text=page_data.get('alt_text', '')
|
||||||
|
)
|
||||||
|
pages.append(page)
|
||||||
|
|
||||||
|
# Create PDF generator and start download
|
||||||
|
pdf_generator = PeeronPDF(set_num, version_num, pages, socket=self)
|
||||||
|
pdf_generator.create_pdf()
|
||||||
|
|
||||||
|
# Refresh instructions list to include new PDF
|
||||||
|
BrickInstructionsList(force=True)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error in download_peeron_pages: {e}")
|
||||||
|
self.fail(message=f"Error downloading Peeron pages: {e}")
|
||||||
|
|
||||||
@self.socket.on(MESSAGES['IMPORT_SET'], namespace=self.namespace)
|
@self.socket.on(MESSAGES['IMPORT_SET'], namespace=self.namespace)
|
||||||
@rebrickable_socket(self)
|
@rebrickable_socket(self)
|
||||||
def import_set(data: dict[str, Any], /) -> None:
|
def import_set(data: dict[str, Any], /) -> None:
|
||||||
|
|||||||
36
wsgi.py
36
wsgi.py
@@ -1,38 +1,18 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
WSGI entry point for BrickTracker - Production Docker deployment
|
WSGI entry point for BrickTracker - Production Docker deployment
|
||||||
This ensures proper gevent monkey patching for gunicorn
|
This ensures proper gevent monkey patching before any imports
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# CRITICAL: This must be the very first import
|
# CRITICAL: Monkey patch must be first, before ANY other imports
|
||||||
import gevent.monkey
|
import gevent.monkey
|
||||||
gevent.monkey.patch_all()
|
gevent.monkey.patch_all()
|
||||||
|
|
||||||
import logging
|
# Now import the regular app factory
|
||||||
import sys
|
from app import create_app
|
||||||
import os
|
|
||||||
|
|
||||||
# Add the current directory to Python path
|
# Create the application - this will be a BrickSocket instance
|
||||||
sys.path.insert(0, os.path.dirname(__file__))
|
app_instance = create_app()
|
||||||
|
|
||||||
# Import Flask and BrickTracker modules directly
|
# For gunicorn, we need the Flask app, not the BrickSocket wrapper
|
||||||
from flask import Flask
|
application = app_instance.app if hasattr(app_instance, 'app') else app_instance
|
||||||
from bricktracker.app import setup_app
|
|
||||||
from bricktracker.socket import BrickSocket
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
# Create the Flask app directly (bypassing app.py to avoid double monkey patching)
|
|
||||||
app = Flask(__name__)
|
|
||||||
|
|
||||||
# Setup the app
|
|
||||||
setup_app(app)
|
|
||||||
|
|
||||||
# Create the socket
|
|
||||||
socket_instance = BrickSocket(
|
|
||||||
app,
|
|
||||||
threaded=not app.config['NO_THREADED_SOCKET'],
|
|
||||||
)
|
|
||||||
|
|
||||||
# Export the Flask app for gunicorn
|
|
||||||
application = app
|
|
||||||
Reference in New Issue
Block a user