rename handler
This commit is contained in:
@@ -9,7 +9,7 @@ from changedetectionio.blueprint.ui.edit import construct_blueprint as construct
|
|||||||
from changedetectionio.blueprint.ui.notification import construct_blueprint as construct_notification_blueprint
|
from changedetectionio.blueprint.ui.notification import construct_blueprint as construct_notification_blueprint
|
||||||
from changedetectionio.blueprint.ui.views import construct_blueprint as construct_views_blueprint
|
from changedetectionio.blueprint.ui.views import construct_blueprint as construct_views_blueprint
|
||||||
|
|
||||||
def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_update_threads, queuedWatchMetaData, watch_check_completed):
|
def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_update_threads, queuedWatchMetaData, watch_check_update):
|
||||||
ui_blueprint = Blueprint('ui', __name__, template_folder="templates")
|
ui_blueprint = Blueprint('ui', __name__, template_folder="templates")
|
||||||
|
|
||||||
# Register the edit blueprint
|
# Register the edit blueprint
|
||||||
@@ -21,10 +21,10 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_updat
|
|||||||
ui_blueprint.register_blueprint(notification_blueprint)
|
ui_blueprint.register_blueprint(notification_blueprint)
|
||||||
|
|
||||||
# Register the views blueprint
|
# Register the views blueprint
|
||||||
views_blueprint = construct_views_blueprint(datastore, update_q, queuedWatchMetaData, watch_check_completed)
|
views_blueprint = construct_views_blueprint(datastore, update_q, queuedWatchMetaData, watch_check_update)
|
||||||
ui_blueprint.register_blueprint(views_blueprint)
|
ui_blueprint.register_blueprint(views_blueprint)
|
||||||
|
|
||||||
ui_ajax_blueprint = constuct_ui_ajax_blueprint(datastore, update_q, running_update_threads, queuedWatchMetaData, watch_check_completed)
|
ui_ajax_blueprint = constuct_ui_ajax_blueprint(datastore, update_q, running_update_threads, queuedWatchMetaData, watch_check_update)
|
||||||
ui_blueprint.register_blueprint(ui_ajax_blueprint)
|
ui_blueprint.register_blueprint(ui_ajax_blueprint)
|
||||||
|
|
||||||
# Import the login decorator
|
# Import the login decorator
|
||||||
@@ -252,7 +252,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, running_updat
|
|||||||
|
|
||||||
if uuids:
|
if uuids:
|
||||||
for uuid in uuids:
|
for uuid in uuids:
|
||||||
watch_check_completed.send(watch_uuid=uuid)
|
watch_check_update.send(watch_uuid=uuid)
|
||||||
|
|
||||||
return redirect(url_for('watchlist.index'))
|
return redirect(url_for('watchlist.index'))
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ from flask import Blueprint, request, redirect, url_for, flash, render_template,
|
|||||||
|
|
||||||
from changedetectionio.store import ChangeDetectionStore
|
from changedetectionio.store import ChangeDetectionStore
|
||||||
|
|
||||||
def constuct_ui_ajax_blueprint(datastore: ChangeDetectionStore, update_q, running_update_threads, queuedWatchMetaData, watch_check_completed):
|
def constuct_ui_ajax_blueprint(datastore: ChangeDetectionStore, update_q, running_update_threads, queuedWatchMetaData, watch_check_update):
|
||||||
ui_ajax_blueprint = Blueprint('ajax', __name__, template_folder="templates", url_prefix='/ajax')
|
ui_ajax_blueprint = Blueprint('ajax', __name__, template_folder="templates", url_prefix='/ajax')
|
||||||
|
|
||||||
# Import the login decorator
|
# Import the login decorator
|
||||||
@@ -25,9 +25,9 @@ def constuct_ui_ajax_blueprint(datastore: ChangeDetectionStore, update_q, runnin
|
|||||||
elif op == 'recheck':
|
elif op == 'recheck':
|
||||||
update_q.put(queuedWatchMetaData.PrioritizedItem(priority=1, item={'uuid': uuid}))
|
update_q.put(queuedWatchMetaData.PrioritizedItem(priority=1, item={'uuid': uuid}))
|
||||||
|
|
||||||
watch_check_completed = signal('watch_check_completed')
|
watch_check_update = signal('watch_check_update')
|
||||||
if watch_check_completed:
|
if watch_check_update:
|
||||||
watch_check_completed.send(watch_uuid=uuid)
|
watch_check_update.send(watch_uuid=uuid)
|
||||||
|
|
||||||
return 'OK'
|
return 'OK'
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ from changedetectionio.store import ChangeDetectionStore
|
|||||||
from changedetectionio.auth_decorator import login_optionally_required
|
from changedetectionio.auth_decorator import login_optionally_required
|
||||||
from changedetectionio import html_tools
|
from changedetectionio import html_tools
|
||||||
|
|
||||||
def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMetaData, watch_check_completed):
|
def construct_blueprint(datastore: ChangeDetectionStore, update_q, queuedWatchMetaData, watch_check_update):
|
||||||
views_blueprint = Blueprint('ui_views', __name__, template_folder="../ui/templates")
|
views_blueprint = Blueprint('ui_views', __name__, template_folder="../ui/templates")
|
||||||
|
|
||||||
@views_blueprint.route("/preview/<string:uuid>", methods=['GET'])
|
@views_blueprint.route("/preview/<string:uuid>", methods=['GET'])
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class SignalPriorityQueue(queue.PriorityQueue):
|
|||||||
if hasattr(item, 'item') and isinstance(item.item, dict) and 'uuid' in item.item:
|
if hasattr(item, 'item') and isinstance(item.item, dict) and 'uuid' in item.item:
|
||||||
uuid = item.item['uuid']
|
uuid = item.item['uuid']
|
||||||
# Get the signal and send it if it exists
|
# Get the signal and send it if it exists
|
||||||
watch_check_completed = signal('watch_check_completed')
|
watch_check_update = signal('watch_check_update')
|
||||||
if watch_check_completed:
|
if watch_check_update:
|
||||||
# Send the watch_uuid parameter
|
# Send the watch_uuid parameter
|
||||||
watch_check_completed.send(watch_uuid=uuid)
|
watch_check_update.send(watch_uuid=uuid)
|
||||||
@@ -33,7 +33,7 @@ from flask_cors import CORS
|
|||||||
|
|
||||||
# Create specific signals for application events
|
# Create specific signals for application events
|
||||||
# Make this a global singleton to avoid multiple signal objects
|
# Make this a global singleton to avoid multiple signal objects
|
||||||
watch_check_completed = signal('watch_check_completed', doc='Signal sent when a watch check is completed')
|
watch_check_update = signal('watch_check_update', doc='Signal sent when a watch check is completed')
|
||||||
from flask_wtf import CSRFProtect
|
from flask_wtf import CSRFProtect
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
import eventlet
|
import eventlet
|
||||||
@@ -245,7 +245,7 @@ def changedetection_app(config=None, datastore_o=None):
|
|||||||
app.config['DATASTORE'] = datastore_o
|
app.config['DATASTORE'] = datastore_o
|
||||||
|
|
||||||
# Store the signal in the app config to ensure it's accessible everywhere
|
# Store the signal in the app config to ensure it's accessible everywhere
|
||||||
app.config['WATCH_CHECK_COMPLETED_SIGNAL'] = watch_check_completed
|
app.config['watch_check_update_SIGNAL'] = watch_check_update
|
||||||
|
|
||||||
login_manager = flask_login.LoginManager(app)
|
login_manager = flask_login.LoginManager(app)
|
||||||
login_manager.login_view = 'login'
|
login_manager.login_view = 'login'
|
||||||
@@ -472,7 +472,7 @@ def changedetection_app(config=None, datastore_o=None):
|
|||||||
|
|
||||||
# watchlist UI buttons etc
|
# watchlist UI buttons etc
|
||||||
import changedetectionio.blueprint.ui as ui
|
import changedetectionio.blueprint.ui as ui
|
||||||
app.register_blueprint(ui.construct_blueprint(datastore, update_q, running_update_threads, queuedWatchMetaData, watch_check_completed))
|
app.register_blueprint(ui.construct_blueprint(datastore, update_q, running_update_threads, queuedWatchMetaData, watch_check_update))
|
||||||
|
|
||||||
import changedetectionio.blueprint.watchlist as watchlist
|
import changedetectionio.blueprint.watchlist as watchlist
|
||||||
app.register_blueprint(watchlist.construct_blueprint(datastore=datastore, update_q=update_q, queuedWatchMetaData=queuedWatchMetaData), url_prefix='')
|
app.register_blueprint(watchlist.construct_blueprint(datastore=datastore, update_q=update_q, queuedWatchMetaData=queuedWatchMetaData), url_prefix='')
|
||||||
|
|||||||
@@ -126,9 +126,9 @@ class model(watch_base):
|
|||||||
'remote_server_reply': None,
|
'remote_server_reply': None,
|
||||||
'track_ldjson_price_data': None
|
'track_ldjson_price_data': None
|
||||||
})
|
})
|
||||||
watch_check_completed = signal('watch_check_completed')
|
watch_check_update = signal('watch_check_update')
|
||||||
if watch_check_completed:
|
if watch_check_update:
|
||||||
watch_check_completed.send(watch_uuid=self.get('uuid'))
|
watch_check_update.send(watch_uuid=self.get('uuid'))
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -5,17 +5,14 @@ import time
|
|||||||
import os
|
import os
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from changedetectionio.flask_app import _jinja2_filter_datetime, watch_check_completed
|
|
||||||
|
|
||||||
|
|
||||||
class SignalHandler:
|
class SignalHandler:
|
||||||
"""A standalone class to receive signals"""
|
"""A standalone class to receive signals"""
|
||||||
def __init__(self, socketio_instance, datastore):
|
def __init__(self, socketio_instance, datastore):
|
||||||
self.socketio_instance = socketio_instance
|
self.socketio_instance = socketio_instance
|
||||||
self.datastore = datastore
|
self.datastore = datastore
|
||||||
|
|
||||||
# Connect to the watch_check_completed signal
|
# Connect to the watch_check_update signal
|
||||||
from changedetectionio.flask_app import watch_check_completed as wcc
|
from changedetectionio.flask_app import watch_check_update as wcc
|
||||||
wcc.connect(self.handle_signal, weak=False)
|
wcc.connect(self.handle_signal, weak=False)
|
||||||
logger.info("SignalHandler: Connected to signal from direct import")
|
logger.info("SignalHandler: Connected to signal from direct import")
|
||||||
|
|
||||||
@@ -42,6 +39,7 @@ def handle_watch_update(socketio, **kwargs):
|
|||||||
|
|
||||||
# Emit the watch update to all connected clients
|
# Emit the watch update to all connected clients
|
||||||
from changedetectionio.flask_app import running_update_threads, update_q
|
from changedetectionio.flask_app import running_update_threads, update_q
|
||||||
|
from changedetectionio.flask_app import _jinja2_filter_datetime
|
||||||
|
|
||||||
# Get list of watches that are currently running
|
# Get list of watches that are currently running
|
||||||
running_uuids = []
|
running_uuids = []
|
||||||
@@ -69,9 +67,10 @@ def handle_watch_update(socketio, **kwargs):
|
|||||||
'notification_muted': True if watch.get('notification_muted') else False,
|
'notification_muted': True if watch.get('notification_muted') else False,
|
||||||
'unviewed': watch.has_unviewed,
|
'unviewed': watch.has_unviewed,
|
||||||
'uuid': watch.get('uuid'),
|
'uuid': watch.get('uuid'),
|
||||||
|
'event_timestamp': time.time()
|
||||||
}
|
}
|
||||||
socketio.emit("watch_update", watch_data)
|
socketio.emit("watch_update", watch_data)
|
||||||
logger.debug(f"Socket.IO: Emitted update for watch {watch.get('uuid')}")
|
logger.debug(f"Socket.IO: Emitted update for watch {watch.get('uuid')}, Checking now: {watch_data['checking_now']}")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Socket.IO error in handle_watch_update: {str(e)}")
|
logger.error(f"Socket.IO error in handle_watch_update: {str(e)}")
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ $(document).ready(function () {
|
|||||||
|
|
||||||
// Listen for periodically emitted watch data
|
// Listen for periodically emitted watch data
|
||||||
socket.on('watch_update', function (watch) {
|
socket.on('watch_update', function (watch) {
|
||||||
console.log(`Watch update ${watch.uuid}`);
|
console.log(`${watch.event_timestamp} - Watch update ${watch.uuid} - Checking now - ${watch.checking_now}`);
|
||||||
|
|
||||||
const $watchRow = $('tr[data-watch-uuid="' + watch.uuid + '"]');
|
const $watchRow = $('tr[data-watch-uuid="' + watch.uuid + '"]');
|
||||||
if ($watchRow.length) {
|
if ($watchRow.length) {
|
||||||
|
|||||||
@@ -167,9 +167,9 @@ class ChangeDetectionStore:
|
|||||||
self.data['watching'][uuid].update({'last_viewed': int(timestamp)})
|
self.data['watching'][uuid].update({'last_viewed': int(timestamp)})
|
||||||
self.needs_write = True
|
self.needs_write = True
|
||||||
|
|
||||||
watch_check_completed = signal('watch_check_completed')
|
watch_check_update = signal('watch_check_update')
|
||||||
if watch_check_completed:
|
if watch_check_update:
|
||||||
watch_check_completed.send(watch_uuid=uuid)
|
watch_check_update.send(watch_uuid=uuid)
|
||||||
|
|
||||||
def remove_password(self):
|
def remove_password(self):
|
||||||
self.__data['settings']['application']['password'] = False
|
self.__data['settings']['application']['password'] = False
|
||||||
|
|||||||
37
changedetectionio/tests/realtime/test_socketio.py
Executable file
37
changedetectionio/tests/realtime/test_socketio.py
Executable file
@@ -0,0 +1,37 @@
|
|||||||
|
import asyncio
|
||||||
|
import socketio
|
||||||
|
|
||||||
|
# URL of your Socket.IO server
|
||||||
|
SOCKETIO_URL = "http://localhost:5000" # Change as needed
|
||||||
|
SOCKETIO_PATH = "/socket.io" # Match the path used in your JS config
|
||||||
|
|
||||||
|
# Number of clients to simulate
|
||||||
|
NUM_CLIENTS = 10
|
||||||
|
|
||||||
|
async def start_client(client_id: int):
|
||||||
|
sio = socketio.AsyncClient(reconnection_attempts=5, reconnection_delay=1)
|
||||||
|
|
||||||
|
@sio.event
|
||||||
|
async def connect():
|
||||||
|
print(f"[Client {client_id}] Connected")
|
||||||
|
|
||||||
|
@sio.event
|
||||||
|
async def disconnect():
|
||||||
|
print(f"[Client {client_id}] Disconnected")
|
||||||
|
|
||||||
|
@sio.on("watch_update")
|
||||||
|
async def on_watch_update(watch):
|
||||||
|
print(f"[Client {client_id}] Received update: {watch}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
await sio.connect(SOCKETIO_URL, socketio_path=SOCKETIO_PATH, transports=["websocket", "polling"])
|
||||||
|
await sio.wait()
|
||||||
|
except Exception as e:
|
||||||
|
print(f"[Client {client_id}] Connection error: {e}")
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
clients = [start_client(i) for i in range(NUM_CLIENTS)]
|
||||||
|
await asyncio.gather(*clients)
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
@@ -2,7 +2,7 @@ from .processors.exceptions import ProcessorException
|
|||||||
import changedetectionio.content_fetchers.exceptions as content_fetchers_exceptions
|
import changedetectionio.content_fetchers.exceptions as content_fetchers_exceptions
|
||||||
from changedetectionio.processors.text_json_diff.processor import FilterNotFoundInResponse
|
from changedetectionio.processors.text_json_diff.processor import FilterNotFoundInResponse
|
||||||
from changedetectionio import html_tools
|
from changedetectionio import html_tools
|
||||||
from changedetectionio.flask_app import watch_check_completed
|
from changedetectionio.flask_app import watch_check_update
|
||||||
|
|
||||||
import importlib
|
import importlib
|
||||||
import os
|
import os
|
||||||
@@ -272,7 +272,7 @@ class update_worker(threading.Thread):
|
|||||||
logger.info(f"Processing watch UUID {uuid} Priority {queued_item_data.priority} URL {watch['url']}")
|
logger.info(f"Processing watch UUID {uuid} Priority {queued_item_data.priority} URL {watch['url']}")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
watch_check_completed.send(watch_uuid=watch['uuid'])
|
watch_check_update.send(watch_uuid=watch['uuid'])
|
||||||
|
|
||||||
# Processor is what we are using for detecting the "Change"
|
# Processor is what we are using for detecting the "Change"
|
||||||
processor = watch.get('processor', 'text_json_diff')
|
processor = watch.get('processor', 'text_json_diff')
|
||||||
@@ -595,8 +595,8 @@ class update_worker(threading.Thread):
|
|||||||
|
|
||||||
# Send signal for watch check completion with the watch data
|
# Send signal for watch check completion with the watch data
|
||||||
if watch:
|
if watch:
|
||||||
logger.info(f"Sending watch_check_completed signal for UUID {watch['uuid']}")
|
logger.info(f"Sending watch_check_update signal for UUID {watch['uuid']}")
|
||||||
watch_check_completed.send(watch_uuid=watch['uuid'])
|
watch_check_update.send(watch_uuid=watch['uuid'])
|
||||||
|
|
||||||
update_handler = None
|
update_handler = None
|
||||||
logger.debug(f"Watch {uuid} done in {time.time()-fetch_start_time:.2f}s")
|
logger.debug(f"Watch {uuid} done in {time.time()-fetch_start_time:.2f}s")
|
||||||
|
|||||||
Reference in New Issue
Block a user