mirror of https://gitlab.com/bashrc2/epicyon
				
				
				
			
		
			
				
	
	
		
			236 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			236 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			Python
		
	
	
| __filename__ = "schedule.py"
 | |
| __author__ = "Bob Mottram"
 | |
| __license__ = "AGPL3+"
 | |
| __version__ = "1.3.0"
 | |
| __maintainer__ = "Bob Mottram"
 | |
| __email__ = "bob@libreserver.org"
 | |
| __status__ = "Production"
 | |
| __module_group__ = "Calendar"
 | |
| 
 | |
| import os
 | |
| import time
 | |
| import datetime
 | |
| from utils import has_object_dict
 | |
| from utils import get_status_number
 | |
| from utils import load_json
 | |
| from utils import is_account_dir
 | |
| from utils import acct_dir
 | |
| from outbox import post_message_to_outbox
 | |
| from session import create_session
 | |
| 
 | |
| 
 | |
| def _update_post_schedule(base_dir: str, handle: str, httpd,
 | |
|                           max_scheduled_posts: int) -> None:
 | |
|     """Checks if posts are due to be delivered and if so moves them to the outbox
 | |
|     """
 | |
|     schedule_index_filename = \
 | |
|         base_dir + '/accounts/' + handle + '/schedule.index'
 | |
|     if not os.path.isfile(schedule_index_filename):
 | |
|         return
 | |
| 
 | |
|     # get the current time as an int
 | |
|     curr_time = datetime.datetime.utcnow()
 | |
|     days_since_epoch = (curr_time - datetime.datetime(1970, 1, 1)).days
 | |
| 
 | |
|     schedule_dir = base_dir + '/accounts/' + handle + '/scheduled/'
 | |
|     index_lines = []
 | |
|     delete_schedule_post = False
 | |
|     nickname = handle.split('@')[0]
 | |
|     with open(schedule_index_filename, 'r') as sched_file:
 | |
|         for line in sched_file:
 | |
|             if ' ' not in line:
 | |
|                 continue
 | |
|             date_str = line.split(' ')[0]
 | |
|             if 'T' not in date_str:
 | |
|                 continue
 | |
|             post_id = line.split(' ', 1)[1].replace('\n', '').replace('\r', '')
 | |
|             post_filename = schedule_dir + post_id + '.json'
 | |
|             if delete_schedule_post:
 | |
|                 # delete extraneous scheduled posts
 | |
|                 if os.path.isfile(post_filename):
 | |
|                     try:
 | |
|                         os.remove(post_filename)
 | |
|                     except OSError:
 | |
|                         print('EX: _update_post_schedule unable to delete ' +
 | |
|                               str(post_filename))
 | |
|                 continue
 | |
|             # create the new index file
 | |
|             index_lines.append(line)
 | |
|             # convert string date to int
 | |
|             post_time = \
 | |
|                 datetime.datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%S%z")
 | |
|             post_time = post_time.replace(tzinfo=None)
 | |
|             post_days_since_epoch = \
 | |
|                 (post_time - datetime.datetime(1970, 1, 1)).days
 | |
|             if days_since_epoch < post_days_since_epoch:
 | |
|                 continue
 | |
|             if days_since_epoch == post_days_since_epoch:
 | |
|                 if curr_time.time().hour < post_time.time().hour:
 | |
|                     continue
 | |
|                 if curr_time.time().minute < post_time.time().minute:
 | |
|                     continue
 | |
|             if not os.path.isfile(post_filename):
 | |
|                 print('WARN: schedule missing post_filename=' + post_filename)
 | |
|                 index_lines.remove(line)
 | |
|                 continue
 | |
|             # load post
 | |
|             post_json_object = load_json(post_filename)
 | |
|             if not post_json_object:
 | |
|                 print('WARN: schedule json not loaded')
 | |
|                 index_lines.remove(line)
 | |
|                 continue
 | |
| 
 | |
|             # set the published time
 | |
|             # If this is not recent then http checks on the receiving side
 | |
|             # will reject it
 | |
|             _, published = get_status_number()
 | |
|             if post_json_object.get('published'):
 | |
|                 post_json_object['published'] = published
 | |
|             if has_object_dict(post_json_object):
 | |
|                 if post_json_object['object'].get('published'):
 | |
|                     post_json_object['published'] = published
 | |
| 
 | |
|             print('Sending scheduled post ' + post_id)
 | |
| 
 | |
|             if nickname:
 | |
|                 httpd.post_to_nickname = nickname
 | |
| 
 | |
|             # create session if needed
 | |
|             curr_session = httpd.session
 | |
|             curr_proxy_type = httpd.proxy_type
 | |
|             if not curr_session:
 | |
|                 curr_session = create_session(httpd.proxy_type)
 | |
|                 httpd.session = curr_session
 | |
|             if not curr_session:
 | |
|                 continue
 | |
| 
 | |
|             if not post_message_to_outbox(curr_session,
 | |
|                                           httpd.translate,
 | |
|                                           post_json_object, nickname,
 | |
|                                           httpd, base_dir,
 | |
|                                           httpd.http_prefix,
 | |
|                                           httpd.domain,
 | |
|                                           httpd.domain_full,
 | |
|                                           httpd.onion_domain,
 | |
|                                           httpd.i2p_domain,
 | |
|                                           httpd.port,
 | |
|                                           httpd.recent_posts_cache,
 | |
|                                           httpd.followers_threads,
 | |
|                                           httpd.federation_list,
 | |
|                                           httpd.send_threads,
 | |
|                                           httpd.postLog,
 | |
|                                           httpd.cached_webfingers,
 | |
|                                           httpd.person_cache,
 | |
|                                           httpd.allow_deletion,
 | |
|                                           curr_proxy_type,
 | |
|                                           httpd.project_version,
 | |
|                                           httpd.debug,
 | |
|                                           httpd.yt_replace_domain,
 | |
|                                           httpd.twitter_replacement_domain,
 | |
|                                           httpd.show_published_date_only,
 | |
|                                           httpd.allow_local_network_access,
 | |
|                                           httpd.city, httpd.system_language,
 | |
|                                           httpd.shared_items_federated_domains,
 | |
|                                           httpd.shared_item_federation_tokens,
 | |
|                                           httpd.low_bandwidth,
 | |
|                                           httpd.signing_priv_key_pem,
 | |
|                                           httpd.peertube_instances,
 | |
|                                           httpd.theme_name,
 | |
|                                           httpd.max_like_count,
 | |
|                                           httpd.max_recent_posts,
 | |
|                                           httpd.cw_lists,
 | |
|                                           httpd.lists_enabled,
 | |
|                                           httpd.content_license_url):
 | |
|                 index_lines.remove(line)
 | |
|                 try:
 | |
|                     os.remove(post_filename)
 | |
|                 except OSError:
 | |
|                     print('EX: _update_post_schedule unable to delete ' +
 | |
|                           str(post_filename))
 | |
|                 continue
 | |
| 
 | |
|             # move to the outbox
 | |
|             outbox_post_filename = \
 | |
|                 post_filename.replace('/scheduled/', '/outbox/')
 | |
|             os.rename(post_filename, outbox_post_filename)
 | |
| 
 | |
|             print('Scheduled post sent ' + post_id)
 | |
| 
 | |
|             index_lines.remove(line)
 | |
|             if len(index_lines) > max_scheduled_posts:
 | |
|                 delete_schedule_post = True
 | |
| 
 | |
|     # write the new schedule index file
 | |
|     schedule_index_file = \
 | |
|         base_dir + '/accounts/' + handle + '/schedule.index'
 | |
|     with open(schedule_index_file, 'w+') as schedule_file:
 | |
|         for line in index_lines:
 | |
|             schedule_file.write(line)
 | |
| 
 | |
| 
 | |
| def run_post_schedule(base_dir: str, httpd, max_scheduled_posts: int):
 | |
|     """Dispatches scheduled posts
 | |
|     """
 | |
|     while True:
 | |
|         time.sleep(60)
 | |
|         # for each account
 | |
|         for _, dirs, _ in os.walk(base_dir + '/accounts'):
 | |
|             for account in dirs:
 | |
|                 if '@' not in account:
 | |
|                     continue
 | |
|                 if not is_account_dir(account):
 | |
|                     continue
 | |
|                 # scheduled posts index for this account
 | |
|                 schedule_index_filename = \
 | |
|                     base_dir + '/accounts/' + account + '/schedule.index'
 | |
|                 if not os.path.isfile(schedule_index_filename):
 | |
|                     continue
 | |
|                 _update_post_schedule(base_dir, account,
 | |
|                                       httpd, max_scheduled_posts)
 | |
|             break
 | |
| 
 | |
| 
 | |
| def run_post_schedule_watchdog(project_version: str, httpd) -> None:
 | |
|     """This tries to keep the scheduled post thread running even if it dies
 | |
|     """
 | |
|     print('THREAD: Starting scheduled post watchdog')
 | |
|     post_schedule_original = \
 | |
|         httpd.thrPostSchedule.clone(run_post_schedule)
 | |
|     httpd.thrPostSchedule.start()
 | |
|     while True:
 | |
|         time.sleep(20)
 | |
|         if httpd.thrPostSchedule.is_alive():
 | |
|             continue
 | |
|         httpd.thrPostSchedule.kill()
 | |
|         print('THREAD: restarting scheduled post watchdog')
 | |
|         httpd.thrPostSchedule = \
 | |
|             post_schedule_original.clone(run_post_schedule)
 | |
|         httpd.thrPostSchedule.start()
 | |
|         print('Restarting scheduled posts...')
 | |
| 
 | |
| 
 | |
| def remove_scheduled_posts(base_dir: str, nickname: str, domain: str) -> None:
 | |
|     """Removes any scheduled posts
 | |
|     """
 | |
|     # remove the index
 | |
|     schedule_index_filename = \
 | |
|         acct_dir(base_dir, nickname, domain) + '/schedule.index'
 | |
|     if os.path.isfile(schedule_index_filename):
 | |
|         try:
 | |
|             os.remove(schedule_index_filename)
 | |
|         except OSError:
 | |
|             print('EX: remove_scheduled_posts unable to delete ' +
 | |
|                   schedule_index_filename)
 | |
|     # remove the scheduled posts
 | |
|     scheduled_dir = acct_dir(base_dir, nickname, domain) + '/scheduled'
 | |
|     if not os.path.isdir(scheduled_dir):
 | |
|         return
 | |
|     for scheduled_post_filename in os.listdir(scheduled_dir):
 | |
|         file_path = os.path.join(scheduled_dir, scheduled_post_filename)
 | |
|         if os.path.isfile(file_path):
 | |
|             try:
 | |
|                 os.remove(file_path)
 | |
|             except OSError:
 | |
|                 print('EX: remove_scheduled_posts unable to delete ' +
 | |
|                       file_path)
 |