From 6c16fa4af1d2706dc6b4f033e4c7b32636ad8f60 Mon Sep 17 00:00:00 2001 From: Schimon Jehudah Date: Wed, 7 Feb 2024 22:24:59 +0000 Subject: [PATCH] Restore support for disabling and enabling feeds. Assign handlers to "self". Towards better handling of subscription and unsubscription. Minor fixes. --- slixfeed/action.py | 9 ++- slixfeed/assets/information.toml | 2 +- slixfeed/sqlite.py | 42 +++++++++++--- slixfeed/task.py | 78 ++++++++++++++------------ slixfeed/version.py | 4 +- slixfeed/xmpp/client.py | 58 +++++++++++--------- slixfeed/xmpp/component.py | 94 ++++++++++++-------------------- slixfeed/xmpp/message.py | 46 ++++++++++++---- slixfeed/xmpp/muc.py | 2 - slixfeed/xmpp/presence.py | 18 ++---- slixfeed/xmpp/process.py | 80 ++++++++++----------------- 11 files changed, 223 insertions(+), 210 deletions(-) diff --git a/slixfeed/action.py b/slixfeed/action.py index 31132de..015f8dd 100644 --- a/slixfeed/action.py +++ b/slixfeed/action.py @@ -143,7 +143,7 @@ async def xmpp_start_updates(self, message, jid, jid_file): else: await sqlite.set_settings_value(db_file, [key, val]) status_type = 'available' - status_message = '💡️ Welcome back!' + status_message = '📫️ Welcome back!' XmppPresence.send(self, jid, status_message, status_type=status_type) message_body = 'Updates are enabled.' XmppMessage.send_reply(self, message, message_body) @@ -159,11 +159,11 @@ async def xmpp_stop_updates(self, message, jid, jid_file): await sqlite.update_settings_value(db_file, [key, val]) else: await sqlite.set_settings_value(db_file, [key, val]) - await task.clean_tasks_xmpp(jid, ['interval', 'status']) + task.clean_tasks_xmpp(self, jid, ['interval', 'status']) message_body = 'Updates are disabled.' XmppMessage.send_reply(self, message, message_body) status_type = 'xa' - status_message = '💡️ Send "Start" to receive Jabber updates' + status_message = '📪️ Send "Start" to receive Jabber updates' XmppPresence.send(self, jid, status_message, status_type=status_type) @@ -1098,8 +1098,7 @@ async def download_document(self, message, jid, jid_file, message_text, ix_url, url = None error = None response = None - if ext in ('epub', 'html', 'markdown', - 'md', 'pdf', 'text', 'txt'): + if ext in ('epub', 'html', 'markdown', 'md', 'pdf', 'text', 'txt'): match ext: case 'markdown': ext = 'md' diff --git a/slixfeed/assets/information.toml b/slixfeed/assets/information.toml index d844dae..a9ba061 100644 --- a/slixfeed/assets/information.toml +++ b/slixfeed/assets/information.toml @@ -61,7 +61,7 @@ No operator was specified for this instance. platforms = """ Supported platforms: XMPP -Platforms to be added in future: Briar, Email, IRC, Matrix, MQTT, Nostr, Tox. +Platforms to be added in future: ActivityPub, Briar, Email, IRC, LXMF, Matrix, MQTT, Nostr, Tox. For ideal experience, we recommend using XMPP. """ diff --git a/slixfeed/sqlite.py b/slixfeed/sqlite.py index 17026fc..8601a0f 100644 --- a/slixfeed/sqlite.py +++ b/slixfeed/sqlite.py @@ -628,7 +628,7 @@ async def get_number_of_feeds_active(db_file): Returns ------- - count : ? + count : str Number of rows. """ with create_connection(db_file) as conn: @@ -1018,7 +1018,7 @@ async def update_statistics(cur): cur.execute(sql, par) -async def set_enabled_status(db_file, ix, status): +async def set_enabled_status(db_file, feed_id, status): """ Set status of feed to enabled or not enabled (i.e. disabled). @@ -1026,8 +1026,8 @@ async def set_enabled_status(db_file, ix, status): ---------- db_file : str Path to database file. - ix : str - Index of entry. + feed_id : str + Index of feed. status : int 0 or 1. """ @@ -1038,12 +1038,12 @@ async def set_enabled_status(db_file, ix, status): """ UPDATE feeds_state SET enabled = :status - WHERE feed_id = :id + WHERE feed_id = :feed_id """ ) par = { "status": status, - "id": ix + "feed_id": feed_id } cur.execute(sql, par) @@ -1395,7 +1395,7 @@ async def get_entries_of_feed(db_file, feed_id): # "feed" urls that are enabled in table "status" async def get_feeds_url(db_file): """ - Query active feeds for URLs. + Query table feeds for URLs. Parameters ---------- @@ -1419,6 +1419,34 @@ async def get_feeds_url(db_file): return result +async def get_active_feeds_url(db_file): + """ + Query table feeds for active URLs. + + Parameters + ---------- + db_file : str + Path to database file. + + Returns + ------- + result : list + URLs of active feeds. + """ + with create_connection(db_file) as conn: + cur = conn.cursor() + sql = ( + """ + SELECT feeds.url + FROM feeds + INNER JOIN feeds_state ON feeds.id = feeds_state.feed_id + WHERE feeds_state.enabled = 1 + """ + ) + result = cur.execute(sql).fetchall() + return result + + async def get_feeds(db_file): """ Query table feeds and list items. diff --git a/slixfeed/task.py b/slixfeed/task.py index a657751..6d73582 100644 --- a/slixfeed/task.py +++ b/slixfeed/task.py @@ -53,9 +53,9 @@ from slixfeed.xmpp.connect import XmppConnect from slixfeed.xmpp.utility import get_chat_type import time -main_task = [] -jid_tasker = {} -task_manager = {} +# main_task = [] +# jid_tasker = {} +# task_manager = {} loop = asyncio.get_event_loop() @@ -71,12 +71,12 @@ loop = asyncio.get_event_loop() def ping_task(self): - global ping_task_instance + # global ping_task_instance try: - ping_task_instance.cancel() + self.ping_task_instance.cancel() except: logging.info('No ping task to cancel.') - ping_task_instance = asyncio.create_task(XmppConnect.ping(self)) + self.ping_task_instance = asyncio.create_task(XmppConnect.ping(self)) """ @@ -94,21 +94,28 @@ await taskhandler.start_tasks( """ async def start_tasks_xmpp(self, jid, tasks=None): + """ + NOTE + + For proper activation of tasks involving task 'interval', it is essential + to place task 'interval' as the last to start due to await asyncio.sleep() + which otherwise would postpone tasks that would be set after task 'interval' + """ if jid == self.boundjid.bare: return try: - task_manager[jid] + self.task_manager[jid] except KeyError as e: - task_manager[jid] = {} + self.task_manager[jid] = {} logging.debug('KeyError:', str(e)) logging.info('Creating new task manager for JID {}'.format(jid)) if not tasks: tasks = ['status', 'check', 'interval'] logging.info('Stopping tasks {} for JID {}'.format(tasks, jid)) for task in tasks: - # if task_manager[jid][task]: + # if self.task_manager[jid][task]: try: - task_manager[jid][task].cancel() + self.task_manager[jid][task].cancel() except: logging.info('No task {} for JID {} (start_tasks_xmpp)' .format(task, jid)) @@ -120,10 +127,10 @@ async def start_tasks_xmpp(self, jid, tasks=None): # breakpoint() match task: case 'check': - task_manager[jid]['check'] = asyncio.create_task( + self.task_manager[jid]['check'] = asyncio.create_task( check_updates(jid)) case 'status': - task_manager[jid]['status'] = asyncio.create_task( + self.task_manager[jid]['status'] = asyncio.create_task( send_status(self, jid)) case 'interval': jid_file = jid.replace('/', '_') @@ -152,11 +159,11 @@ async def start_tasks_xmpp(self, jid, tasks=None): await sqlite.update_last_update_time(db_file) else: await sqlite.set_last_update_time(db_file) - task_manager[jid]['interval'] = asyncio.create_task( + self.task_manager[jid]['interval'] = asyncio.create_task( send_update(self, jid)) - # for task in task_manager[jid].values(): + # for task in self.task_manager[jid].values(): # print("task_manager[jid].values()") - # print(task_manager[jid].values()) + # print(self.task_manager[jid].values()) # print("task") # print(task) # print("jid") @@ -165,14 +172,14 @@ async def start_tasks_xmpp(self, jid, tasks=None): # await task -async def clean_tasks_xmpp(jid, tasks=None): +def clean_tasks_xmpp(self, jid, tasks=None): if not tasks: tasks = ['interval', 'status', 'check'] logging.info('Stopping tasks {} for JID {}'.format(tasks, jid)) for task in tasks: - # if task_manager[jid][task]: + # if self.task_manager[jid][task]: try: - task_manager[jid][task].cancel() + self.task_manager[jid][task].cancel() except: logging.debug('No task {} for JID {} (clean_tasks_xmpp)' .format(task, jid)) @@ -230,6 +237,8 @@ async def send_update(self, jid, num=None): media = await action.extract_image_from_html(url) if media and news_digest: + print('SENDING MESSAGE (if media and news_digest)') + print(news_digest) # Send textual message XmppMessage.send(self, jid, news_digest, chat_type) news_digest = '' @@ -238,6 +247,8 @@ async def send_update(self, jid, num=None): media = None if news_digest: + print('SENDING MESSAGE (if news_digest)') + print(news_digest) # TODO Add while loop to assure delivery. # print(await current_time(), ">>> ACT send_message",jid) # NOTE Do we need "if statement"? See NOTE at is_muc. @@ -255,14 +266,13 @@ async def send_update(self, jid, num=None): # TODO Do not refresh task before # verifying that it was completed. - await refresh_task( - self, jid, send_update, 'interval') + await refresh_task(self, jid, send_update, 'interval') # interval = await initdb( # jid, # sqlite.get_settings_value, # "interval" # ) - # task_manager[jid]["interval"] = loop.call_at( + # self.task_manager[jid]["interval"] = loop.call_at( # loop.time() + 60 * interval, # loop.create_task, # send_update(jid) @@ -298,7 +308,7 @@ async def send_status(self, jid): enabled = await config.get_setting_value(db_file, 'enabled') if not enabled: status_mode = 'xa' - status_text = '📫️ Send "Start" to receive updates' + status_text = '📪️ Send "Start" to receive updates' else: feeds = await sqlite.get_number_of_items(db_file, 'feeds') # print(await current_time(), jid, "has", feeds, "feeds") @@ -350,29 +360,29 @@ async def refresh_task(self, jid, callback, key, val=None): jid_file = jid.replace('/', '_') db_file = config.get_pathname_to_database(jid_file) val = await config.get_setting_value(db_file, key) - # if task_manager[jid][key]: - if jid in task_manager: + # if self.task_manager[jid][key]: + if jid in self.task_manager: try: - task_manager[jid][key].cancel() + self.task_manager[jid][key].cancel() except: logging.info('No task of type {} to cancel for ' 'JID {} (refresh_task)'.format(key, jid) ) - # task_manager[jid][key] = loop.call_at( + # self.task_manager[jid][key] = loop.call_at( # loop.time() + 60 * float(val), # loop.create_task, # (callback(self, jid)) # # send_update(jid) # ) - task_manager[jid][key] = loop.create_task( + self.task_manager[jid][key] = loop.create_task( wait_and_run(self, callback, jid, val) ) - # task_manager[jid][key] = loop.call_later( + # self.task_manager[jid][key] = loop.call_later( # 60 * float(val), # loop.create_task, # send_update(jid) # ) - # task_manager[jid][key] = send_update.loop.call_at( + # self.task_manager[jid][key] = send_update.loop.call_at( # send_update.loop.time() + 60 * val, # send_update.loop.create_task, # send_update(jid) @@ -399,7 +409,7 @@ async def check_updates(jid): while True: jid_file = jid.replace('/', '_') db_file = config.get_pathname_to_database(jid_file) - urls = await sqlite.get_feeds_url(db_file) + urls = await sqlite.get_active_feeds_url(db_file) for url in urls: await action.scan(db_file, url) val = config.get_value('settings', 'Settings', 'check') @@ -416,7 +426,7 @@ async def check_updates(jid): NOTE This is an older system, utilizing local storage instead of XMPP presence. This function is good for use with protocols that might not have presence. -ActivityPub, IRC, LXMF, Matrix, SMTP, Tox. +ActivityPub, IRC, LXMF, Matrix, Nostr, SMTP, Tox. """ async def select_file(self): """ @@ -446,10 +456,8 @@ async def select_file(self): if (file.endswith('.db') and not file.endswith('.db-jour.db')): jid = file[:-3] - main_task.extend( - [tg.create_task(self.task_jid(jid))] - ) + main_task.extend([tg.create_task(self.task_jid(jid))]) # main_task = [tg.create_task(self.task_jid(jid))] - # task_manager.update({jid: tg}) + # self.task_manager.update({jid: tg}) diff --git a/slixfeed/version.py b/slixfeed/version.py index aa3d55f..dffadd2 100644 --- a/slixfeed/version.py +++ b/slixfeed/version.py @@ -1,2 +1,2 @@ -__version__ = '0.1.1' -__version_info__ = (0, 1, 1) +__version__ = '0.1.2' +__version_info__ = (0, 1, 2) diff --git a/slixfeed/xmpp/client.py b/slixfeed/xmpp/client.py index 1eb4adb..ba2a6d5 100644 --- a/slixfeed/xmpp/client.py +++ b/slixfeed/xmpp/client.py @@ -100,12 +100,20 @@ class Slixfeed(slixmpp.ClientXMPP): # NOTE # The bot works fine when the nickname is hardcoded; or # The bot won't join some MUCs when its nickname has brackets + + # Handler for nickname self.alias = alias - # The session_start event will be triggered when - # the bot establishes its connection with the server - # and the XML streams are ready for use. We want to - # listen for this event so that we we can initialize - # our roster. + + # Handlers for tasks + self.task_manager = {} + + # Handlers for ping + self.ping_task_instance = {} + + # Handlers for connection events + self.connection_attempts = 0 + self.max_connection_attempts = 10 + self.add_event_handler("session_start", self.on_session_start) self.add_event_handler("session_resumed", @@ -158,9 +166,6 @@ class Slixfeed(slixmpp.ClientXMPP): # Initialize event loop # self.loop = asyncio.get_event_loop() - # handlers for connection events - self.connection_attempts = 0 - self.max_connection_attempts = 10 self.add_event_handler('connection_failed', self.on_connection_failed) self.add_event_handler('session_end', @@ -174,8 +179,7 @@ class Slixfeed(slixmpp.ClientXMPP): muc_jid = message['groupchat_invite']['jid'] await XmppBookmark.add(self, muc_jid) await XmppGroupchat.join(self, inviter, muc_jid) - message_body = ('Greetings!\n' - 'I am {}, the news anchor.\n' + message_body = ('Greetings! I am {}, the news anchor.\n' 'My job is to bring you the latest ' 'news from sources you provide me with.\n' 'You may always reach me via xmpp:{}?message' @@ -189,8 +193,7 @@ class Slixfeed(slixmpp.ClientXMPP): muc_jid = message['groupchat_invite']['jid'] await XmppBookmark.add(self, muc_jid) await XmppGroupchat.join(self, inviter, muc_jid) - message_body = ('Greetings!\n' - 'I am {}, the news anchor.\n' + message_body = ('Greetings! I am {}, the news anchor.\n' 'My job is to bring you the latest ' 'news from sources you provide me with.\n' 'You may always reach me via xmpp:{}?message' @@ -260,14 +263,14 @@ class Slixfeed(slixmpp.ClientXMPP): # await task.check_readiness(self, presence) jid = presence['from'].bare if presence['show'] in ('away', 'dnd', 'xa'): - await task.clean_tasks_xmpp(jid, ['interval']) + task.clean_tasks_xmpp(self, jid, ['interval']) await task.start_tasks_xmpp(self, jid, ['status', 'check']) async def on_presence_subscribe(self, presence): jid = presence['from'].bare if not self.client_roster[jid]['to']: - XmppPresence.subscribe(self, jid) + XmppPresence.subscription(self, jid, 'subscribe') await XmppRoster.add(self, jid) status_message = '✒️ Share online status to receive updates' XmppPresence.send(self, jid, status_message) @@ -280,8 +283,7 @@ class Slixfeed(slixmpp.ClientXMPP): async def on_presence_subscribed(self, presence): jid = presence['from'].bare message_subject = 'RSS News Bot' - message_body = ('Greetings!\n' - 'I am {}, the news anchor.\n' + message_body = ('Greetings! I am {}, the news anchor.\n' 'My job is to bring you the latest ' 'news from sources you provide me with.\n' 'You may always reach me via xmpp:{}?message' @@ -304,17 +306,19 @@ class Slixfeed(slixmpp.ClientXMPP): async def on_presence_unsubscribed(self, presence): jid = presence['from'].bare message_body = 'You have been unsubscribed.' - status_message = '🖋️ Subscribe to receive updates' + # status_message = '🖋️ Subscribe to receive updates' + # status_message = None XmppMessage.send(self, jid, message_body, 'chat') - XmppPresence.send(self, jid, status_message, - presence_type='unsubscribed') + XmppPresence.subscription(self, jid, 'unsubscribe') + # XmppPresence.send(self, jid, status_message, + # presence_type='unsubscribed') await XmppRoster.remove(self, jid) async def on_presence_unavailable(self, presence): jid = presence['from'].bare # await task.stop_tasks(self, jid) - await task.clean_tasks_xmpp(jid) + task.clean_tasks_xmpp(self, jid) # TODO @@ -326,7 +330,7 @@ class Slixfeed(slixmpp.ClientXMPP): print("on_presence_error") print(presence) jid = presence["from"].bare - await task.clean_tasks_xmpp(jid) + task.clean_tasks_xmpp(self, jid) async def on_reactions(self, message): @@ -337,36 +341,36 @@ class Slixfeed(slixmpp.ClientXMPP): async def on_chatstate_active(self, message): if message['type'] in ('chat', 'normal'): jid = message['from'].bare - # await task.clean_tasks_xmpp(jid, ['status']) + # task.clean_tasks_xmpp(self, jid, ['status']) await task.start_tasks_xmpp(self, jid, ['status']) async def on_chatstate_composing(self, message): if message['type'] in ('chat', 'normal'): jid = message['from'].bare - # await task.clean_tasks_xmpp(jid, ['status']) - status_message='Press "help" for manual, or "info" for information.' + # task.clean_tasks_xmpp(self, jid, ['status']) + status_message='💡 Press "help" for manual, or "info" for information.' XmppPresence.send(self, jid, status_message) async def on_chatstate_gone(self, message): if message['type'] in ('chat', 'normal'): jid = message['from'].bare - # await task.clean_tasks_xmpp(jid, ['status']) + # task.clean_tasks_xmpp(self, jid, ['status']) await task.start_tasks_xmpp(self, jid, ['status']) async def on_chatstate_inactive(self, message): if message['type'] in ('chat', 'normal'): jid = message['from'].bare - # await task.clean_tasks_xmpp(jid, ['status']) + # task.clean_tasks_xmpp(self, jid, ['status']) await task.start_tasks_xmpp(self, jid, ['status']) async def on_chatstate_paused(self, message): if message['type'] in ('chat', 'normal'): jid = message['from'].bare - # await task.clean_tasks_xmpp(jid, ['status']) + # task.clean_tasks_xmpp(self, jid, ['status']) await task.start_tasks_xmpp(self, jid, ['status']) diff --git a/slixfeed/xmpp/component.py b/slixfeed/xmpp/component.py index 44a2405..53391db 100644 --- a/slixfeed/xmpp/component.py +++ b/slixfeed/xmpp/component.py @@ -3,44 +3,10 @@ """ -FIXME - -1) Function check_readiness or event "changed_status" is causing for - triple status messages and also false ones that indicate of lack - of feeds. - TODO -1) Use loop (with gather) instead of TaskGroup. - -2) Assure message delivery before calling a new task. - See https://slixmpp.readthedocs.io/en/latest/event_index.html#term-marker_acknowledged - -3) XHTTML-IM - case _ if message_lowercase.startswith("html"): - message['html']=" -Parse me! -" - self.send_message( - mto=jid, - mfrom=self.boundjid.bare, - mhtml=message - ) - -NOTE - -1) Self presence - Apparently, it is possible to view self presence. - This means that there is no need to store presences in order to switch or restore presence. - check_readiness - 📂 Send a URL from a blog or a news website. - JID: self.boundjid.bare - MUC: self.alias - -2) Extracting attribute using xmltodict. - import xmltodict - message = xmltodict.parse(str(message)) - jid = message["message"]["x"]["@jid"] +1) Look into self.set_jid in order to be able to join to groupchats + https://slixmpp.readthedocs.io/en/latest/api/basexmpp.html#slixmpp.basexmpp.BaseXMPP.set_jid """ @@ -97,11 +63,23 @@ class SlixfeedComponent(slixmpp.ComponentXMPP): def __init__(self, jid, secret, hostname, port, alias=None): slixmpp.ComponentXMPP.__init__(self, jid, secret, hostname, port) - # The session_start event will be triggered when - # the bot establishes its connection with the server - # and the XML streams are ready for use. We want to - # listen for this event so that we we can initialize - # our roster. + # NOTE + # The bot works fine when the nickname is hardcoded; or + # The bot won't join some MUCs when its nickname has brackets + + # Handler for nickname + self.alias = alias + + # Handlers for tasks + self.task_manager = {} + + # Handlers for ping + self.ping_task_instance = {} + + # Handlers for connection events + self.connection_attempts = 0 + self.max_connection_attempts = 10 + self.add_event_handler("session_start", self.on_session_start) self.add_event_handler("session_resumed", @@ -154,9 +132,6 @@ class SlixfeedComponent(slixmpp.ComponentXMPP): # Initialize event loop # self.loop = asyncio.get_event_loop() - # handlers for connection events - self.connection_attempts = 0 - self.max_connection_attempts = 10 self.add_event_handler('connection_failed', self.on_connection_failed) self.add_event_handler('session_end', @@ -241,21 +216,20 @@ class SlixfeedComponent(slixmpp.ComponentXMPP): # await task.check_readiness(self, presence) jid = presence['from'].bare if presence['show'] in ('away', 'dnd', 'xa'): - await task.clean_tasks_xmpp(jid, ['interval']) + task.clean_tasks_xmpp(self, jid, ['interval']) await task.start_tasks_xmpp(self, jid, ['status', 'check']) async def on_presence_subscribe(self, presence): jid = presence['from'].bare # XmppPresence.request(self, jid) - XmppPresence.subscribe(self, jid) + XmppPresence.subscription(self, jid, 'subscribe') async def on_presence_subscribed(self, presence): jid = presence['from'].bare message_subject = 'RSS News Bot' - message_body = ('Greetings!\n' - 'I am {}, the news anchor.\n' + message_body = ('Greetings! I am {}, the news anchor.\n' 'My job is to bring you the latest ' 'news from sources you provide me with.\n' 'You may always reach me via xmpp:{}?message' @@ -278,16 +252,18 @@ class SlixfeedComponent(slixmpp.ComponentXMPP): async def on_presence_unsubscribed(self, presence): jid = presence['from'].bare message_body = 'You have been unsubscribed.' - status_message = '🖋️ Subscribe to receive updates' + # status_message = '🖋️ Subscribe to receive updates' + # status_message = None XmppMessage.send(self, jid, message_body, 'chat') - XmppPresence.send(self, jid, status_message, - presence_type='unsubscribed') + XmppPresence.subscription(self, jid, 'unsubscribe') + # XmppPresence.send(self, jid, status_message, + # presence_type='unsubscribed') async def on_presence_unavailable(self, presence): jid = presence['from'].bare # await task.stop_tasks(self, jid) - await task.clean_tasks_xmpp(jid) + task.clean_tasks_xmpp(self, jid) # TODO @@ -299,7 +275,7 @@ class SlixfeedComponent(slixmpp.ComponentXMPP): print("on_presence_error") print(presence) jid = presence["from"].bare - await task.clean_tasks_xmpp(jid) + task.clean_tasks_xmpp(self, jid) async def on_reactions(self, message): @@ -310,36 +286,36 @@ class SlixfeedComponent(slixmpp.ComponentXMPP): async def on_chatstate_active(self, message): if message['type'] in ('chat', 'normal'): jid = message['from'].bare - # await task.clean_tasks_xmpp(jid, ['status']) + # task.clean_tasks_xmpp(self, jid, ['status']) await task.start_tasks_xmpp(self, jid, ['status']) async def on_chatstate_composing(self, message): if message['type'] in ('chat', 'normal'): jid = message['from'].bare - # await task.clean_tasks_xmpp(jid, ['status']) - status_message='Press "help" for manual, or "info" for information.' + # task.clean_tasks_xmpp(self, jid, ['status']) + status_message='💡 Press "help" for manual, or "info" for information.' XmppPresence.send(self, jid, status_message) async def on_chatstate_gone(self, message): if message['type'] in ('chat', 'normal'): jid = message['from'].bare - # await task.clean_tasks_xmpp(jid, ['status']) + # task.clean_tasks_xmpp(self, jid, ['status']) await task.start_tasks_xmpp(self, jid, ['status']) async def on_chatstate_inactive(self, message): if message['type'] in ('chat', 'normal'): jid = message['from'].bare - # await task.clean_tasks_xmpp(jid, ['status']) + # task.clean_tasks_xmpp(self, jid, ['status']) await task.start_tasks_xmpp(self, jid, ['status']) async def on_chatstate_paused(self, message): if message['type'] in ('chat', 'normal'): jid = message['from'].bare - # await task.clean_tasks_xmpp(jid, ['status']) + # task.clean_tasks_xmpp(self, jid, ['status']) await task.start_tasks_xmpp(self, jid, ['status']) diff --git a/slixfeed/xmpp/message.py b/slixfeed/xmpp/message.py index 2c7cb52..9ce1833 100644 --- a/slixfeed/xmpp/message.py +++ b/slixfeed/xmpp/message.py @@ -24,6 +24,28 @@ NOTE See XEP-0367: Message Attaching +FIXME + +ERROR:asyncio:Task exception was never retrieved +future: exception=ParseError('not well-formed (invalid token): line 1, column 198')> +Traceback (most recent call last): + File "/home/jojo/.venv/lib/python3.11/site-packages/slixfeed/task.py", line 237, in send_update + XmppMessage.send_oob(self, jid, media, chat_type) + File "/home/jojo/.venv/lib/python3.11/site-packages/slixfeed/xmpp/message.py", line 56, in send_oob + message = self.make_message(mto=jid, + ^^^^^^^^^^^^^^^^^^^^^^^^^^ + File "/home/jojo/.venv/lib/python3.11/site-packages/slixmpp/basexmpp.py", line 517, in make_message + message['html']['body'] = mhtml + ~~~~~~~~~~~~~~~^^^^^^^^ + File "/home/jojo/.venv/lib/python3.11/site-packages/slixmpp/xmlstream/stanzabase.py", line 792, in __setitem__ + getattr(self, set_method)(value, **kwargs) + File "/home/jojo/.venv/lib/python3.11/site-packages/slixmpp/plugins/xep_0071/stanza.py", line 38, in set_body + xhtml = ET.fromstring(content) + ^^^^^^^^^^^^^^^^^^^^^^ + File "/usr/lib/python3.11/xml/etree/ElementTree.py", line 1338, in XML + parser.feed(text) +xml.etree.ElementTree.ParseError: not well-formed (invalid token): line 1, column 198 + """ class XmppMessage: @@ -50,16 +72,20 @@ class XmppMessage: def send_oob(self, jid, url, chat_type): - html = ( - f'' - f'{url}') - message = self.make_message(mto=jid, - mfrom=self.boundjid.bare, - mbody=url, - mhtml=html, - mtype=chat_type) - message['oob']['url'] = url - message.send() + try: + html = ( + f'' + f'{url}') + message = self.make_message(mto=jid, + mfrom=self.boundjid.bare, + mbody=url, + mhtml=html, + mtype=chat_type) + message['oob']['url'] = url + message.send() + except: + logging.error('ERROR!') + logging.error(jid, url, chat_type, html) # FIXME Solve this function diff --git a/slixfeed/xmpp/muc.py b/slixfeed/xmpp/muc.py index 8dcb100..3202633 100644 --- a/slixfeed/xmpp/muc.py +++ b/slixfeed/xmpp/muc.py @@ -17,8 +17,6 @@ FIXME """ import logging -from slixfeed.dt import current_time -from slixfeed.xmpp.message import XmppMessage class XmppGroupchat: diff --git a/slixfeed/xmpp/presence.py b/slixfeed/xmpp/presence.py index b586408..387c5b6 100644 --- a/slixfeed/xmpp/presence.py +++ b/slixfeed/xmpp/presence.py @@ -7,6 +7,10 @@ NOTE Accept symbols 🉑️ 👍️ ✍ +TODO + +Remove subscription from JID that do not (stopped) share presence. + """ class XmppPresence: @@ -20,18 +24,8 @@ class XmppPresence: ptype=presence_type) - def subscribe(self, jid): + def subscription(self, jid, presence_type): self.send_presence_subscription(pto=jid, pfrom=self.boundjid.bare, - ptype='subscribe', + ptype=presence_type, pnick=self.alias) - - - def remove(self): - """ - Remove subscription from JID that do not (stopped) share presence. - - Returns - ------- - None. - """ diff --git a/slixfeed/xmpp/process.py b/slixfeed/xmpp/process.py index b166ba0..f32caeb 100644 --- a/slixfeed/xmpp/process.py +++ b/slixfeed/xmpp/process.py @@ -86,7 +86,7 @@ async def message(self, message): if (message_text.lower().startswith('http') and message_text.lower().endswith('.opml')): url = message_text - await task.clean_tasks_xmpp(jid, ['status']) + task.clean_tasks_xmpp(self, jid, ['status']) status_type = 'dnd' status_message = '📥️ Procesing request to import feeds...' XmppPresence.send(self, jid, status_message, @@ -97,7 +97,7 @@ async def message(self, message): response = 'Successfully imported {} feeds.'.format(count) else: response = 'OPML file was not imported.' - # await task.clean_tasks_xmpp(jid, ['status']) + # task.clean_tasks_xmpp(self, jid, ['status']) await task.start_tasks_xmpp(self, jid, ['status']) XmppMessage.send_reply(self, message, response) return @@ -296,7 +296,7 @@ async def message(self, message): await action.scan(db_file, url) old = await config.get_setting_value(db_file, "old") if old: - # await task.clean_tasks_xmpp(jid, ['status']) + # task.clean_tasks_xmpp(self, jid, ['status']) # await send_status(jid) await task.start_tasks_xmpp(self, jid, ['status']) else: @@ -489,33 +489,25 @@ async def message(self, message): # case _ if (message_lowercase.startswith('http')) and( # message_lowercase.endswith('.opml')): # url = message_text - # await task.clean_tasks_xmpp( - # jid, ['status']) + # task.clean_tasks_xmpp(self, jid, ['status']) # status_type = 'dnd' - # status_message = ( - # '📥️ Procesing request to import feeds...' - # ) - # XmppPresence.send( - # self, jid, status_message, status_type=status_type) + # status_message = '📥️ Procesing request to import feeds...' + # XmppPresence.send(self, jid, status_message, + # status_type=status_type) # db_file = config.get_pathname_to_database(jid_file) # count = await action.import_opml(db_file, url) # if count: - # response = ( - # 'Successfully imported {} feeds.' - # ).format(count) + # response = ('Successfully imported {} feeds.' + # .format(count)) # else: - # response = ( - # 'OPML file was not imported.' - # ) - # await task.clean_tasks_xmpp( - # jid, ['status']) - # await task.start_tasks_xmpp( - # self, jid, ['status']) + # response = 'OPML file was not imported.' + # task.clean_tasks_xmpp(self, jid, ['status']) + # await task.start_tasks_xmpp(self, jid, ['status']) # XmppMessage.send_reply(self, message, response) case _ if (message_lowercase.startswith('http') or message_lowercase.startswith('feed:')): url = message_text - # await task.clean_tasks_xmpp(jid, ['status']) + # task.clean_tasks_xmpp(self, jid, ['status']) status_type = 'dnd' status_message = ('📫️ Processing request ' 'to fetch data from {}' @@ -528,7 +520,7 @@ async def message(self, message): db_file = config.get_pathname_to_database(jid_file) # try: response = await action.add_feed(db_file, url) - # await task.clean_tasks_xmpp(jid, ['status']) + # task.clean_tasks_xmpp(self, jid, ['status']) await task.start_tasks_xmpp(self, jid, ['status']) # except: # response = ( @@ -641,25 +633,11 @@ async def message(self, message): await task.send_update(self, jid) - # await task.clean_tasks_xmpp( - # jid, ['interval', 'status']) - # await task.start_tasks_xmpp( - # self, jid, ['interval', 'status']) + # task.clean_tasks_xmpp(self, jid, ['interval', 'status']) + # await task.start_tasks_xmpp(self, jid, ['status', 'interval']) - # await refresh_task( - # self, - # jid, - # send_update, - # 'interval', - # num - # ) - # await refresh_task( - # self, - # jid, - # send_status, - # 'status', - # 20 - # ) + # await refresh_task(self, jid, send_update, 'interval', num) + # await refresh_task(self, jid, send_status, 'status', 20) # await refresh_task(jid, key, val) case 'old': db_file = config.get_pathname_to_database(jid_file) @@ -703,7 +681,7 @@ async def message(self, message): data = message_text[5:] data = data.split() url = data[0] - await task.clean_tasks_xmpp(jid, ['status']) + task.clean_tasks_xmpp(self, jid, ['status']) status_type = 'dnd' status_message = ('📫️ Processing request to fetch data from {}' .format(url)) @@ -787,7 +765,7 @@ async def message(self, message): # 'status', # 20 # ) - # await task.clean_tasks_xmpp(jid, ['status']) + # task.clean_tasks_xmpp(self, jid, ['status']) await task.start_tasks_xmpp(self, jid, ['status']) else: response = 'Missing feed URL or index number.' @@ -795,7 +773,7 @@ async def message(self, message): case _ if message_lowercase.startswith('reset'): # TODO Reset also by ID ix_url = message_text[6:] - await task.clean_tasks_xmpp(jid, ['status']) + task.clean_tasks_xmpp(self, jid, ['status']) status_type = 'dnd' status_message = '📫️ Marking entries as read...' XmppPresence.send(self, jid, status_message, @@ -859,22 +837,24 @@ async def message(self, message): response = await action.list_statistics(db_file) XmppMessage.send_reply(self, message, response) case _ if message_lowercase.startswith('disable '): - ix = message_text[8:] + feed_id = message_text[8:] db_file = config.get_pathname_to_database(jid_file) try: - await sqlite.set_enabled_status(db_file, ix, 0) + await sqlite.set_enabled_status(db_file, feed_id, 0) + await sqlite.mark_feed_as_read(db_file, feed_id) response = ('Updates are now disabled for news source {}.' - .format(ix)) + .format(feed_id)) except: - response = 'No news source with index {}.'.format(ix) + response = 'No news source with index {}.'.format(feed_id) XmppMessage.send_reply(self, message, response) + await task.start_tasks_xmpp(self, jid, ['status']) case _ if message_lowercase.startswith('enable'): - ix = message_text[7:] + feed_id = message_text[7:] db_file = config.get_pathname_to_database(jid_file) try: - await sqlite.set_enabled_status(db_file, ix, 1) + await sqlite.set_enabled_status(db_file, feed_id, 1) response = ('Updates are now enabled for news source {}.' - .format(ix)) + .format(feed_id)) except: response = 'No news source with index {}.'.format(ix) XmppMessage.send_reply(self, message, response)