Add Gajim to the list of recommended clients;
Improve PEP and PubSub publishing mechanism.
This commit is contained in:
parent
640677437c
commit
263382ba8d
8 changed files with 123 additions and 79 deletions
|
@ -123,10 +123,6 @@ def main():
|
|||
# Setup logging.
|
||||
logging.basicConfig(level=args.loglevel,
|
||||
format='%(levelname)-8s %(message)s')
|
||||
|
||||
# # Setup logging.
|
||||
# logging.basicConfig(level=args.loglevel,
|
||||
# format='%(levelname)-8s %(message)s')
|
||||
# # logging.basicConfig(format='[%(levelname)s] %(message)s')
|
||||
# logger = logging.getLogger()
|
||||
# logdbg = logger.debug
|
||||
|
|
|
@ -653,10 +653,15 @@ or on your desktop.
|
|||
url = "https://conversejs.org"
|
||||
platform = "HTML (Web)"
|
||||
|
||||
# [[clients]]
|
||||
# name = "Gajim"
|
||||
# info = "XMPP client for desktop"
|
||||
# url = "https://gajim.org"
|
||||
[[clients]]
|
||||
name = "Gajim"
|
||||
info = "XMPP client for desktop"
|
||||
info = ["""
|
||||
Gajim aims to be an easy to use and fully-featured XMPP client. \
|
||||
It is open source and released under the GNU General Public License (GPL).
|
||||
"""]
|
||||
url = "https://gajim.org"
|
||||
platform = "Any"
|
||||
|
||||
# [[clients]]
|
||||
# name = "Monal IM"
|
||||
|
|
|
@ -19,6 +19,8 @@ import logging
|
|||
|
||||
class Logger:
|
||||
|
||||
def set_logging_level(level):
|
||||
logging.basicConfig(level)
|
||||
|
||||
def __init__(self, name):
|
||||
self.logger = logging.getLogger(name)
|
||||
|
|
|
@ -1278,7 +1278,7 @@ class FeedTask:
|
|||
db_file = config.get_pathname_to_database(jid_bare)
|
||||
urls = sqlite.get_active_feeds_url_sorted_by_last_scanned(db_file)
|
||||
for url in urls:
|
||||
Message.printer('Scanning updates for URL {} ...'.format(url))
|
||||
#Message.printer('Scanning updates for URL {} ...'.format(url))
|
||||
url = url[0]
|
||||
# print('STA',url)
|
||||
|
||||
|
|
|
@ -161,7 +161,7 @@ class XmppChat:
|
|||
# Adding one to the length because of
|
||||
# assumption that a comma or a dot is added
|
||||
alias_of_slixfeed_length = len(alias_of_slixfeed) + 1
|
||||
command = (command[alias_of_slixfeed_length:]).lstrip()
|
||||
command = command[alias_of_slixfeed_length:].lstrip()
|
||||
if isinstance(command, Message): command = command['body']
|
||||
|
||||
command_lowercase = command.lower()
|
||||
|
|
|
@ -26,6 +26,9 @@ NOTE
|
|||
message = xmltodict.parse(str(message))
|
||||
jid = message["message"]["x"]["@jid"]
|
||||
|
||||
2) It seems that XmppRoster.get_contacts(self) is being used excessively.
|
||||
Use self.client_roster instead.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
|
@ -383,9 +386,20 @@ class XmppClient(slixmpp.ClientXMPP):
|
|||
print('POSIX sockets: Initiating IPC server...')
|
||||
self.ipc = asyncio.create_task(XmppIpcServer.ipc(self))
|
||||
|
||||
results = await XmppPubsub.get_pubsub_services(self)
|
||||
for result in results + [{'jid' : self.boundjid.bare,
|
||||
'name' : self.alias}]:
|
||||
jids_of_pubsub = await XmppPubsub.get_pubsub_services(self)
|
||||
for jid_bare in jids_of_pubsub:
|
||||
jid_bare['type'] = 'pubsub'
|
||||
# NOTE Do you need 'name' too, or only 'jid'?
|
||||
#jids_of_roster = []
|
||||
#for jid_bare in self.client_roster:
|
||||
# jids_of_roster.append({'jid' : jid_bare,
|
||||
# 'name' : '',
|
||||
# 'type' : 'pep'})
|
||||
jid_of_slixfeed = [{'jid' : self.boundjid.bare,
|
||||
'name' : self.alias,
|
||||
'type' : 'pep'}]
|
||||
#for result in jids_of_pubsub + jids_of_roster + jid_of_slixfeed:
|
||||
for result in jids_of_pubsub + jid_of_slixfeed:
|
||||
jid_bare = result['jid']
|
||||
if jid_bare not in self.settings:
|
||||
db_file = config.get_pathname_to_database(jid_bare)
|
||||
|
@ -399,8 +413,12 @@ class XmppClient(slixmpp.ClientXMPP):
|
|||
# asyncio.create_task(FeedTask.loop_task(self, jid_bare))
|
||||
#]
|
||||
#await asyncio.gather(*tasks)
|
||||
print('feed task for {}'.format(jid_bare))
|
||||
asyncio.create_task(FeedTask.loop_task(self, jid_bare))
|
||||
asyncio.create_task(XmppPubsubTask.loop_task(self, jid_bare)),
|
||||
#await asyncio.sleep(10)
|
||||
print('publish task for {}'.format(jid_bare))
|
||||
publish_type = result['type']
|
||||
asyncio.create_task(XmppPubsubTask.loop_task(self, jid_bare, publish_type)),
|
||||
print('End')
|
||||
|
||||
time_end = time.time()
|
||||
|
@ -1802,7 +1820,7 @@ class XmppClient(slixmpp.ClientXMPP):
|
|||
identifier = values['identifier'] if 'identifier' in values else None
|
||||
url = values['subscription']
|
||||
jid_bare = session['from'].bare
|
||||
if 'jid' in values: custom_jid = values['jid']
|
||||
custom_jid = values['jid'] if 'jid' in values else None
|
||||
if XmppUtilities.is_operator(self, jid_bare) and custom_jid:
|
||||
if isinstance(custom_jid, list): custom_jid = custom_jid[0]
|
||||
jid_bare = custom_jid or jid_bare
|
||||
|
@ -1929,14 +1947,16 @@ class XmppClient(slixmpp.ClientXMPP):
|
|||
entries = sqlite.get_entries_of_feed(db_file, feed_id)
|
||||
renewed, scanned = sqlite.get_last_update_time_of_feed(db_file,
|
||||
feed_id)
|
||||
last_updated_string = renewed or scanned
|
||||
last_updated = DateAndTime.convert_seconds_to_yyyy_mm_dd(
|
||||
float(renewed or scanned))
|
||||
float(last_updated_string)) if last_updated_string else 'N/A'
|
||||
form.add_field(desc='Recent titles from subscription',
|
||||
ftype='fixed',
|
||||
value='Recent updates')
|
||||
recent_updates = ''
|
||||
for entry in entries:
|
||||
recent_updates += '* ' + entry[1] + '\n\n'
|
||||
if not recent_updates: recent_updates = 'N/A'
|
||||
form.add_field(ftype='text-multi',
|
||||
value=recent_updates)
|
||||
form.add_field(ftype='fixed',
|
||||
|
|
|
@ -10,10 +10,13 @@ class XmppIQ:
|
|||
|
||||
async def send(self, iq):
|
||||
try:
|
||||
await iq.send(timeout=15)
|
||||
result = await iq.send(timeout=15)
|
||||
except IqTimeout as e:
|
||||
logger.error('Error Timeout')
|
||||
logger.error(str(e))
|
||||
result = e
|
||||
except IqError as e:
|
||||
logger.error('Error XmppIQ')
|
||||
logger.error(str(e))
|
||||
result = e
|
||||
return result
|
||||
|
|
|
@ -44,10 +44,10 @@ class XmppPubsub:
|
|||
return results
|
||||
|
||||
|
||||
async def get_node_properties(self, jid, node):
|
||||
config = await self.plugin['xep_0060'].get_node_config(jid, node)
|
||||
subscriptions = await self.plugin['xep_0060'].get_node_subscriptions(jid, node)
|
||||
affiliations = await self.plugin['xep_0060'].get_node_affiliations(jid, node)
|
||||
async def get_node_properties(self, jid_bare, node):
|
||||
config = await self.plugin['xep_0060'].get_node_config(jid_bare, node)
|
||||
subscriptions = await self.plugin['xep_0060'].get_node_subscriptions(jid_bare, node)
|
||||
affiliations = await self.plugin['xep_0060'].get_node_affiliations(jid_bare, node)
|
||||
properties = {'config': config,
|
||||
'subscriptions': subscriptions,
|
||||
'affiliations': affiliations}
|
||||
|
@ -55,49 +55,48 @@ class XmppPubsub:
|
|||
return properties
|
||||
|
||||
|
||||
async def get_node_configuration(self, jid, node_id):
|
||||
node = await self.plugin['xep_0060'].get_node_config(jid, node_id)
|
||||
if not node:
|
||||
print('NODE CONFIG', node_id, str(node))
|
||||
|
||||
async def get_node_configuration(self, jid_bare, node_id):
|
||||
node = await self.plugin['xep_0060'].get_node_config(jid_bare, node_id)
|
||||
return node
|
||||
|
||||
|
||||
async def get_nodes(self, jid):
|
||||
nodes = await self.plugin['xep_0060'].get_nodes(jid)
|
||||
async def get_nodes(self, jid_bare):
|
||||
nodes = await self.plugin['xep_0060'].get_nodes(jid_bare)
|
||||
# 'self' would lead to slixmpp.jid.InvalidJID: idna validation failed:
|
||||
return nodes
|
||||
|
||||
|
||||
async def get_item(self, jid, node, item_id):
|
||||
item = await self.plugin['xep_0060'].get_item(jid, node, item_id)
|
||||
async def get_item(self, jid_bare, node, item_id):
|
||||
item = await self.plugin['xep_0060'].get_item(jid_bare, node, item_id)
|
||||
return item
|
||||
|
||||
|
||||
async def get_items(self, jid, node):
|
||||
items = await self.plugin['xep_0060'].get_items(jid, node)
|
||||
async def get_items(self, jid_bare, node):
|
||||
items = await self.plugin['xep_0060'].get_items(jid_bare, node)
|
||||
return items
|
||||
|
||||
|
||||
def delete_node(self, jid, node):
|
||||
jid_from = str(self.boundjid) if self.is_component else None
|
||||
self.plugin['xep_0060'].delete_node(jid, node, ifrom=jid_from)
|
||||
def delete_node(self, jid_bare, node):
|
||||
jid_from = self.boundjid.bare if self.is_component else None
|
||||
self.plugin['xep_0060'].delete_node(jid_bare, node, ifrom=jid_from)
|
||||
|
||||
|
||||
def purge_node(self, jid, node):
|
||||
jid_from = str(self.boundjid) if self.is_component else None
|
||||
self.plugin['xep_0060'].purge(jid, node, ifrom=jid_from)
|
||||
def purge_node(self, jid_bare, node):
|
||||
jid_from = self.boundjid.bare if self.is_component else None
|
||||
self.plugin['xep_0060'].purge(jid_bare, node, ifrom=jid_from)
|
||||
# iq = self.Iq(stype='set',
|
||||
# sto=jid,
|
||||
# sto=jid_bare,
|
||||
# sfrom=jid_from)
|
||||
# iq['pubsub']['purge']['node'] = node
|
||||
# return iq
|
||||
|
||||
|
||||
# TODO Make use of var "xep" with match/case (XEP-0060, XEP-0277, XEP-0472)
|
||||
def create_node(self, jid, node, xep ,title=None, subtitle=None):
|
||||
jid_from = str(self.boundjid) if self.is_component else None
|
||||
def create_node(self, jid_bare, node, xep=None ,title=None, subtitle=None):
|
||||
jid_from = self.boundjid.bare if self.is_component else None
|
||||
iq = self.Iq(stype='set',
|
||||
sto=jid,
|
||||
sto=jid_bare,
|
||||
sfrom=jid_from)
|
||||
iq['pubsub']['create']['node'] = node
|
||||
form = iq['pubsub']['configure']['form']
|
||||
|
@ -131,8 +130,8 @@ class XmppPubsub:
|
|||
|
||||
# TODO Consider to create a separate function called "create_atom_entry"
|
||||
# or "create_rfc4287_entry" for anything related to variable "node_entry".
|
||||
def create_entry(self, jid, node_id, item_id, node_item):
|
||||
iq = self.Iq(stype="set", sto=jid)
|
||||
def create_entry(self, jid_bare, node_id, item_id, node_item):
|
||||
iq = self.Iq(stype="set", sto=jid_bare)
|
||||
iq['pubsub']['publish']['node'] = node_id
|
||||
|
||||
item = pubsub.Item()
|
||||
|
@ -153,8 +152,8 @@ class XmppPubsub:
|
|||
return iq
|
||||
|
||||
|
||||
def _create_entry(self, jid, node, entry, version):
|
||||
iq = self.Iq(stype="set", sto=jid)
|
||||
def _create_entry(self, jid_bare, node, entry, version):
|
||||
iq = self.Iq(stype="set", sto=jid_bare)
|
||||
iq['pubsub']['publish']['node'] = node
|
||||
|
||||
item = pubsub.Item()
|
||||
|
@ -294,13 +293,15 @@ class XmppPubsubAction:
|
|||
return report
|
||||
|
||||
|
||||
async def send_unread_items(self, jid_bare):
|
||||
async def send_unread_items(self, jid_bare, publish_type):
|
||||
"""
|
||||
|
||||
Parameters
|
||||
----------
|
||||
jid_bare : TYPE
|
||||
jid_bare : str
|
||||
Bare Jabber ID.
|
||||
publish_type : str
|
||||
To which type of PubSub ('pep' or 'pubsub').
|
||||
|
||||
Returns
|
||||
-------
|
||||
|
@ -323,38 +324,56 @@ class XmppPubsubAction:
|
|||
|
||||
# Publish to node 'urn:xmpp:microblog:0' for own JID
|
||||
# Publish to node based on feed identifier for PubSub service.
|
||||
|
||||
if jid_bare == self.boundjid.bare:
|
||||
node_id = 'urn:xmpp:microblog:0'
|
||||
node_subtitle = None
|
||||
node_title = None
|
||||
else:
|
||||
# node_id = feed_properties[2]
|
||||
# node_title = feed_properties[3]
|
||||
# node_subtitle = feed_properties[5]
|
||||
node_id = sqlite.get_feed_identifier(db_file, feed_id)
|
||||
node_id = node_id[0]
|
||||
if not node_id:
|
||||
counter = 0
|
||||
while True:
|
||||
identifier = String.generate_identifier(url, counter)
|
||||
if sqlite.check_identifier_exist(db_file, identifier):
|
||||
counter += 1
|
||||
else:
|
||||
break
|
||||
await sqlite.update_feed_identifier(db_file, feed_id, identifier)
|
||||
|
||||
match publish_type:
|
||||
# XEP-0163: Personal Eventing Protocol
|
||||
# 2.2 One Publisher Per Node¶
|
||||
# The owner-publisher for every node is the bare JID of the account owner.
|
||||
case 'pep':
|
||||
node_id = 'urn:xmpp:microblog:0'
|
||||
node_subtitle = None
|
||||
node_title = None
|
||||
case 'pubsub':
|
||||
# node_id = feed_properties[2]
|
||||
# node_title = feed_properties[3]
|
||||
# node_subtitle = feed_properties[5]
|
||||
node_id = sqlite.get_feed_identifier(db_file, feed_id)
|
||||
node_id = node_id[0]
|
||||
node_title = sqlite.get_feed_title(db_file, feed_id)
|
||||
node_title = node_title[0]
|
||||
node_subtitle = sqlite.get_feed_subtitle(db_file, feed_id)
|
||||
node_subtitle = node_subtitle[0]
|
||||
if not node_id:
|
||||
counter = 0
|
||||
while True:
|
||||
identifier = String.generate_identifier(url, counter)
|
||||
if sqlite.check_identifier_exist(db_file, identifier):
|
||||
counter += 1
|
||||
else:
|
||||
break
|
||||
await sqlite.update_feed_identifier(db_file, feed_id, identifier)
|
||||
node_id = sqlite.get_feed_identifier(db_file, feed_id)
|
||||
node_id = node_id[0]
|
||||
node_title = sqlite.get_feed_title(db_file, feed_id)
|
||||
node_title = node_title[0]
|
||||
node_subtitle = sqlite.get_feed_subtitle(db_file, feed_id)
|
||||
node_subtitle = node_subtitle[0]
|
||||
print ([jid_bare, publish_type, node_id])
|
||||
xep = None
|
||||
node_exist = await XmppPubsub.get_node_configuration(self, jid_bare, node_id)
|
||||
#node_exist = await XmppPubsub.get_node_configuration(self, jid_bare, node_id)
|
||||
nodes = await XmppPubsub.get_nodes(self, jid_bare)
|
||||
node_items = nodes['disco_items']['items']
|
||||
node_exist = False
|
||||
for node_item in node_items:
|
||||
if node_item[1] == node_id:
|
||||
node_exist = True
|
||||
break
|
||||
print(['node_exist', node_exist])
|
||||
if not node_exist:
|
||||
iq_create_node = XmppPubsub.create_node(
|
||||
self, jid_bare, node_id, xep, node_title, node_subtitle)
|
||||
await XmppIQ.send(self, iq_create_node)
|
||||
result = await XmppIQ.send(self, iq_create_node)
|
||||
result_condition = result.iq['error']['condition']
|
||||
if result_condition in ('forbidden', 'service-unavailable'):
|
||||
reason = result.iq['error']['text']
|
||||
print('Creation of node {} for JID {} has failed'.format(node_id, jid_bare, reason))
|
||||
return
|
||||
entries = sqlite.get_unread_entries_of_feed(db_file, feed_id)
|
||||
report[url] = len(entries)
|
||||
for entry in entries:
|
||||
|
@ -362,12 +381,11 @@ class XmppPubsubAction:
|
|||
node_entry = Feed.create_rfc4287_entry(feed_entry)
|
||||
entry_url = feed_entry['link']
|
||||
item_id = Utilities.hash_url_to_md5(entry_url)
|
||||
print('PubSub node item was sent to', jid_bare, node_id)
|
||||
print(entry_url)
|
||||
print(item_id)
|
||||
print(['PubSub node item was sent to', jid_bare, node_id])
|
||||
print([entry_url, item_id])
|
||||
iq_create_entry = XmppPubsub.create_entry(
|
||||
self, jid_bare, node_id, item_id, node_entry)
|
||||
await XmppIQ.send(self, iq_create_entry)
|
||||
result = await XmppIQ.send(self, iq_create_entry)
|
||||
ix = entry[0]
|
||||
await sqlite.mark_as_read(db_file, ix)
|
||||
print(report)
|
||||
|
@ -377,7 +395,7 @@ class XmppPubsubAction:
|
|||
class XmppPubsubTask:
|
||||
|
||||
|
||||
async def loop_task(self, jid_bare):
|
||||
async def loop_task(self, jid_bare, publish_type):
|
||||
db_file = config.get_pathname_to_database(jid_bare)
|
||||
if jid_bare not in self.settings:
|
||||
Config.add_settings_jid(self, jid_bare, db_file)
|
||||
|
@ -394,7 +412,7 @@ class XmppPubsubTask:
|
|||
.format(jid_bare))
|
||||
logger.info('Starting tasks "publish" for JID {}'.format(jid_bare))
|
||||
self.task_manager[jid_bare]['publish'] = asyncio.create_task(
|
||||
XmppPubsubAction.send_unread_items(self, jid_bare))
|
||||
XmppPubsubAction.send_unread_items(self, jid_bare, publish_type))
|
||||
await asyncio.sleep(60 * 180)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue