epicyon/schedule.py

199 lines
7.8 KiB
Python
Raw Normal View History

2020-04-04 10:52:30 +00:00
__filename__ = "schedule.py"
__author__ = "Bob Mottram"
__license__ = "AGPL3+"
2021-01-26 10:07:42 +00:00
__version__ = "1.2.0"
2020-04-04 10:52:30 +00:00
__maintainer__ = "Bob Mottram"
__email__ = "bob@freedombone.net"
__status__ = "Production"
2021-06-15 15:08:12 +00:00
__module_group__ = "Calendar"
2020-01-12 20:13:44 +00:00
import os
2020-01-12 20:16:33 +00:00
import time
2020-01-12 20:13:44 +00:00
import datetime
from utils import hasObjectDict
2020-01-13 11:36:42 +00:00
from utils import getStatusNumber
2020-01-12 21:47:36 +00:00
from utils import loadJson
2021-07-04 17:55:29 +00:00
from utils import isAccountDir
2021-07-13 21:59:53 +00:00
from utils import acctDir
2020-01-13 10:45:02 +00:00
from outbox import postMessageToOutbox
2020-01-12 20:13:44 +00:00
2020-04-04 10:52:30 +00:00
def _updatePostSchedule(baseDir: str, handle: str, httpd,
maxScheduledPosts: int) -> None:
2020-01-12 20:13:44 +00:00
"""Checks if posts are due to be delivered and if so moves them to the outbox
"""
2020-04-04 10:52:30 +00:00
scheduleIndexFilename = baseDir + '/accounts/' + handle + '/schedule.index'
2020-01-12 20:13:44 +00:00
if not os.path.isfile(scheduleIndexFilename):
return
# get the current time as an int
2020-04-04 10:52:30 +00:00
currTime = datetime.datetime.utcnow()
daysSinceEpoch = (currTime - datetime.datetime(1970, 1, 1)).days
2020-01-12 20:13:44 +00:00
2020-04-04 10:52:30 +00:00
scheduleDir = baseDir + '/accounts/' + handle + '/scheduled/'
indexLines = []
deleteSchedulePost = False
nickname = handle.split('@')[0]
2020-01-12 20:13:44 +00:00
with open(scheduleIndexFilename, 'r') as fp:
for line in fp:
if ' ' not in line:
continue
2020-04-04 10:52:30 +00:00
dateStr = line.split(' ')[0]
2020-01-12 20:13:44 +00:00
if 'T' not in dateStr:
continue
2020-05-22 11:32:38 +00:00
postId = line.split(' ', 1)[1].replace('\n', '').replace('\r', '')
2020-04-04 10:52:30 +00:00
postFilename = scheduleDir + postId + '.json'
2020-01-12 20:13:44 +00:00
if deleteSchedulePost:
# delete extraneous scheduled posts
if os.path.isfile(postFilename):
os.remove(postFilename)
continue
# create the new index file
indexLines.append(line)
# convert string date to int
2020-04-04 10:52:30 +00:00
postTime = \
datetime.datetime.strptime(dateStr, "%Y-%m-%dT%H:%M:%S%z")
postTime = postTime.replace(tzinfo=None)
postDaysSinceEpoch = \
(postTime - datetime.datetime(1970, 1, 1)).days
2020-01-12 20:13:44 +00:00
if daysSinceEpoch < postDaysSinceEpoch:
continue
2020-01-13 11:16:35 +00:00
if daysSinceEpoch == postDaysSinceEpoch:
if currTime.time().hour < postTime.time().hour:
continue
if currTime.time().minute < postTime.time().minute:
continue
2020-01-12 20:13:44 +00:00
if not os.path.isfile(postFilename):
2020-04-04 10:52:30 +00:00
print('WARN: schedule missing postFilename=' + postFilename)
2020-01-12 20:13:44 +00:00
indexLines.remove(line)
continue
# load post
2020-04-04 10:52:30 +00:00
postJsonObject = loadJson(postFilename)
2020-01-12 20:13:44 +00:00
if not postJsonObject:
2020-01-13 11:13:30 +00:00
print('WARN: schedule json not loaded')
2020-01-12 20:13:44 +00:00
indexLines.remove(line)
continue
2020-01-13 11:36:42 +00:00
# set the published time
# If this is not recent then http checks on the receiving side
# will reject it
2020-04-04 10:52:30 +00:00
statusNumber, published = getStatusNumber()
2020-01-13 11:36:42 +00:00
if postJsonObject.get('published'):
2020-04-04 10:52:30 +00:00
postJsonObject['published'] = published
if hasObjectDict(postJsonObject):
if postJsonObject['object'].get('published'):
postJsonObject['published'] = published
2020-01-13 11:36:42 +00:00
2020-04-04 10:52:30 +00:00
print('Sending scheduled post ' + postId)
2020-01-12 20:13:44 +00:00
2020-01-13 12:27:27 +00:00
if nickname:
2020-04-04 10:52:30 +00:00
httpd.postToNickname = nickname
if not postMessageToOutbox(httpd.session,
httpd.translate,
postJsonObject, nickname,
2020-04-04 10:52:30 +00:00
httpd, baseDir,
httpd.httpPrefix,
httpd.domain,
httpd.domainFull,
httpd.onionDomain,
2020-06-03 20:21:44 +00:00
httpd.i2pDomain,
2020-04-04 10:52:30 +00:00
httpd.port,
httpd.recentPostsCache,
httpd.followersThreads,
httpd.federationList,
httpd.sendThreads,
httpd.postLog,
httpd.cachedWebfingers,
httpd.personCache,
httpd.allowDeletion,
2020-06-09 11:03:59 +00:00
httpd.proxyType,
2020-04-04 10:52:30 +00:00
httpd.projectVersion,
httpd.debug,
httpd.YTReplacementDomain,
httpd.showPublishedDateOnly,
2021-05-09 19:11:05 +00:00
httpd.allowLocalNetworkAccess,
httpd.city, httpd.systemLanguage,
httpd.sharedItemsFederatedDomains,
httpd.sharedItemFederationTokens):
2020-01-12 20:13:44 +00:00
indexLines.remove(line)
2020-01-13 11:36:42 +00:00
os.remove(postFilename)
2020-01-12 20:13:44 +00:00
continue
# move to the outbox
2021-07-04 17:55:29 +00:00
outboxPostFilename = postFilename.replace('/scheduled/',
'/outbox/')
2020-04-04 10:52:30 +00:00
os.rename(postFilename, outboxPostFilename)
2020-01-12 20:13:44 +00:00
2020-04-04 10:52:30 +00:00
print('Scheduled post sent ' + postId)
2020-01-12 20:13:44 +00:00
indexLines.remove(line)
2020-04-04 10:52:30 +00:00
if len(indexLines) > maxScheduledPosts:
deleteSchedulePost = True
2020-01-12 20:13:44 +00:00
# write the new schedule index file
2020-04-04 10:52:30 +00:00
scheduleIndexFile = \
baseDir + '/accounts/' + handle + '/schedule.index'
2021-06-22 12:27:10 +00:00
with open(scheduleIndexFile, 'w+') as scheduleFile:
2020-01-12 20:13:44 +00:00
for line in indexLines:
scheduleFile.write(line)
2020-04-04 10:52:30 +00:00
def runPostSchedule(baseDir: str, httpd, maxScheduledPosts: int):
2020-01-12 20:13:44 +00:00
"""Dispatches scheduled posts
"""
while True:
time.sleep(60)
# for each account
2020-04-04 10:52:30 +00:00
for subdir, dirs, files in os.walk(baseDir + '/accounts'):
2020-01-12 20:13:44 +00:00
for account in dirs:
if '@' not in account:
continue
2021-07-04 17:55:29 +00:00
if not isAccountDir(account):
2021-01-09 21:47:52 +00:00
continue
2020-01-12 20:13:44 +00:00
# scheduled posts index for this account
2020-04-04 10:52:30 +00:00
scheduleIndexFilename = \
baseDir + '/accounts/' + account + '/schedule.index'
2020-01-12 21:15:42 +00:00
if not os.path.isfile(scheduleIndexFilename):
2020-01-12 20:13:44 +00:00
continue
_updatePostSchedule(baseDir, account, httpd, maxScheduledPosts)
2021-06-05 12:57:24 +00:00
break
2020-01-12 20:13:44 +00:00
2020-04-04 10:52:30 +00:00
def runPostScheduleWatchdog(projectVersion: str, httpd) -> None:
2020-01-12 20:13:44 +00:00
"""This tries to keep the scheduled post thread running even if it dies
"""
print('Starting scheduled post watchdog')
2020-04-04 10:52:30 +00:00
postScheduleOriginal = \
2020-01-12 20:13:44 +00:00
httpd.thrPostSchedule.clone(runPostSchedule)
httpd.thrPostSchedule.start()
while True:
2020-03-22 21:16:02 +00:00
time.sleep(20)
2021-06-05 12:43:57 +00:00
if httpd.thrPostSchedule.is_alive():
continue
httpd.thrPostSchedule.kill()
httpd.thrPostSchedule = \
postScheduleOriginal.clone(runPostSchedule)
httpd.thrPostSchedule.start()
print('Restarting scheduled posts...')
2020-01-14 10:23:17 +00:00
2020-04-04 10:52:30 +00:00
def removeScheduledPosts(baseDir: str, nickname: str, domain: str) -> None:
2020-01-14 10:23:17 +00:00
"""Removes any scheduled posts
"""
# remove the index
2020-04-04 10:52:30 +00:00
scheduleIndexFilename = \
2021-07-13 21:59:53 +00:00
acctDir(baseDir, nickname, domain) + '/schedule.index'
2020-01-14 10:23:17 +00:00
if os.path.isfile(scheduleIndexFilename):
os.remove(scheduleIndexFilename)
# remove the scheduled posts
2021-07-13 21:59:53 +00:00
scheduledDir = acctDir(baseDir, nickname, domain) + '/scheduled'
2020-01-14 10:23:17 +00:00
if not os.path.isdir(scheduledDir):
return
for scheduledPostFilename in os.listdir(scheduledDir):
2020-04-04 10:52:30 +00:00
filePath = os.path.join(scheduledDir, scheduledPostFilename)
2020-01-14 10:23:17 +00:00
try:
if os.path.isfile(filePath):
os.remove(filePath)
2020-04-04 10:52:30 +00:00
except BaseException:
2020-01-14 10:23:17 +00:00
pass