Idea to fetch all UID's in background

This commit is contained in:
the-djmaze 2023-11-27 14:36:46 +01:00
parent 612aa09071
commit 771c6f7559
3 changed files with 147 additions and 92 deletions

View file

@ -673,108 +673,117 @@ class MailClient
throw new \InvalidArgumentException('THREAD not supported'); throw new \InvalidArgumentException('THREAD not supported');
} }
if (!$oInfo->MESSAGES) {
$this->logWrite('No messages in '.$oMessageCollection->FolderName);
return $oMessageCollection;
}
if (!$oParams->iThreadUid) { if (!$oParams->iThreadUid) {
$oMessageCollection->NewMessages = $this->getFolderNextMessageInformation( $oMessageCollection->NewMessages = $this->getFolderNextMessageInformation(
$oParams->sFolderName, $oParams->iPrevUidNext, $oInfo->UIDNEXT $oParams->sFolderName, $oParams->iPrevUidNext, $oInfo->UIDNEXT
); );
} }
if ($oInfo->MESSAGES) { $bUseSort = $oParams->bUseSort || $oParams->sSort;
$bUseSort = $oParams->bUseSort || $oParams->sSort; $aAllThreads = [];
$aAllThreads = []; $aUnseenUIDs = [];
$aUnseenUIDs = []; $aUids = [];
$aUids = [];
$message_list_limit = $this->oImapClient->Settings->message_list_limit; $message_list_limit = $oParams->bIgnoreLimit ? 0 : $this->oImapClient->Settings->message_list_limit;
if (0 < $message_list_limit && $message_list_limit < $oInfo->MESSAGES) { if (0 < $message_list_limit && $message_list_limit < $oInfo->MESSAGES) {
// if ((0 < $message_list_limit && $message_list_limit < $oInfo->MESSAGES) /*
// || (!$this->oImapClient->hasCapability('SORT') && !$this->oImapClient->CapabilityValue('THREAD'))) { // TODO: Idea to fetch all UID's in background
// Don't use THREAD for speed // Must know what is cached so needs more thought
$oMessageCollection->Limited = true; \SnappyMail\Shutdown::add(function($oMailClient, $oParams) {
$this->logWrite('List optimization (count: '.$oInfo->MESSAGES.', limit:'.$message_list_limit.')'); $oParams->bIgnoreLimit = true;
if (\strlen($sSearch)) { $oMailClient->MessageList($oParams);
// Don't use SORT for speed }, [$this, $oParams]);
$aUids = $this->GetUids($oParams, $sSearch, $oInfo/*, $bUseSort*/); */
} else { // if ((0 < $message_list_limit && $message_list_limit < $oInfo->MESSAGES)
$bUseSort = $this->oImapClient->hasCapability('SORT'); // || (!$this->oImapClient->hasCapability('SORT') && !$this->oImapClient->CapabilityValue('THREAD'))) {
if (2 > $oInfo->MESSAGES) { // Don't use THREAD for speed
$aRequestIndexes = \array_slice([1], $oParams->iOffset, 1); $oMessageCollection->Limited = true;
} else if ($bUseSort) { $this->logWrite('List optimization (count: '.$oInfo->MESSAGES.', limit:'.$message_list_limit.')');
// Attempt to sort REVERSE DATE with a bigger range then $oParams->iLimit if (\strlen($sSearch)) {
$end = \min($oInfo->MESSAGES, \max(1, $oInfo->MESSAGES - $oParams->iOffset + $oParams->iLimit)); // Don't use SORT for speed
$start = \max(1, $end - ($oParams->iLimit * 3) + 1); $aUids = $this->GetUids($oParams, $sSearch, $oInfo/*, $bUseSort*/);
$oParams->oSequenceSet = new SequenceSet(\range($end, $start), false);
$aRequestIndexes = $this->GetUids($oParams, '', $oInfo, $bUseSort);
// Attempt to get the correct $oParams->iLimit slice
$aRequestIndexes = \array_slice($aRequestIndexes, $oParams->iOffset ? $oParams->iLimit : 0, $oParams->iLimit);
} else {
// Fetch ID's from high to low
$end = \max(1, $oInfo->MESSAGES - $oParams->iOffset);
$start = \max(1, $end - $oParams->iLimit + 1);
$aRequestIndexes = \range($end, $start);
}
$this->MessageListByRequestIndexOrUids($oMessageCollection, new SequenceSet($aRequestIndexes, false));
}
} else { } else {
$aUids = ($bUseThreads && $oParams->iThreadUid) $bUseSort = $this->oImapClient->hasCapability('SORT');
? [$oParams->iThreadUid] if (2 > $oInfo->MESSAGES) {
: $this->GetUids($oParams, '', $oInfo, $bUseSort); $aRequestIndexes = \array_slice([1], $oParams->iOffset, 1);
} else if ($bUseSort) {
if ($bUseThreads) { // Attempt to sort REVERSE DATE with a bigger range then $oParams->iLimit
$aAllThreads = $this->MessageListThreadsMap($oMessageCollection, $oParams->oCacher); $end = \min($oInfo->MESSAGES, \max(1, $oInfo->MESSAGES - $oParams->iOffset + $oParams->iLimit));
$oMessageCollection->totalThreads = \count($aAllThreads); $start = \max(1, $end - ($oParams->iLimit * 3) + 1);
// $iThreadLimit = $this->oImapClient->Settings->thread_limit; $oParams->oSequenceSet = new SequenceSet(\range($end, $start), false);
if ($oParams->iThreadUid) { $aRequestIndexes = $this->GetUids($oParams, '', $oInfo, $bUseSort);
// Only show the selected thread messages // Attempt to get the correct $oParams->iLimit slice
foreach ($aAllThreads as $aMap) { $aRequestIndexes = \array_slice($aRequestIndexes, $oParams->iOffset ? $oParams->iLimit : 0, $oParams->iLimit);
if (\in_array($oParams->iThreadUid, $aMap)) { } else {
$aUids = $aMap; // Fetch ID's from high to low
break; $end = \max(1, $oInfo->MESSAGES - $oParams->iOffset);
} $start = \max(1, $end - $oParams->iLimit + 1);
} $aRequestIndexes = \range($end, $start);
$aAllThreads = [$aUids];
// This only speeds up the search when not cached
// $oParams->oSequenceSet = new SequenceSet($aUids);
} else {
// Remove all threaded UID's except the most recent of each thread
$threadedUids = [];
foreach ($aAllThreads as $aMap) {
unset($aMap[\array_key_last($aMap)]);
$threadedUids = \array_merge($threadedUids, $aMap);
}
$aUids = \array_diff($aUids, $threadedUids);
// Get all unseen
$aUnseenUIDs = $this->MessageListUnseen($oParams, $oInfo);
}
} }
$this->MessageListByRequestIndexOrUids($oMessageCollection, new SequenceSet($aRequestIndexes, false));
if ($aUids && \strlen($sSearch)) {
$aSearchedUids = $this->GetUids($oParams, $sSearch, $oInfo/*, $bUseSort*/);
if ($bUseThreads && !$oParams->iThreadUid) {
$matchingThreadUids = [];
foreach ($aAllThreads as $aMap) {
if (\array_intersect($aSearchedUids, $aMap)) {
$matchingThreadUids = \array_merge($matchingThreadUids, $aMap);
}
}
$aUids = \array_filter($aUids, function($iUid) use ($aSearchedUids, $matchingThreadUids) {
return \in_array($iUid, $aSearchedUids) || \in_array($iUid, $matchingThreadUids);
});
} else {
$aUids = \array_filter($aUids, function($iUid) use ($aSearchedUids) {
return \in_array($iUid, $aSearchedUids);
});
}
}
}
if (\count($aUids)) {
$oMessageCollection->totalEmails = \count($aUids);
$aUids = \array_slice($aUids, $oParams->iOffset, $oParams->iLimit);
$this->MessageListByRequestIndexOrUids($oMessageCollection, new SequenceSet($aUids), $aAllThreads, $aUnseenUIDs);
} }
} else { } else {
$this->logWrite('No messages in '.$oMessageCollection->FolderName); $aUids = ($bUseThreads && $oParams->iThreadUid)
? [$oParams->iThreadUid]
: $this->GetUids($oParams, '', $oInfo, $bUseSort);
if ($bUseThreads) {
$aAllThreads = $this->MessageListThreadsMap($oMessageCollection, $oParams->oCacher);
$oMessageCollection->totalThreads = \count($aAllThreads);
// $iThreadLimit = $this->oImapClient->Settings->thread_limit;
if ($oParams->iThreadUid) {
// Only show the selected thread messages
foreach ($aAllThreads as $aMap) {
if (\in_array($oParams->iThreadUid, $aMap)) {
$aUids = $aMap;
break;
}
}
$aAllThreads = [$aUids];
// This only speeds up the search when not cached
// $oParams->oSequenceSet = new SequenceSet($aUids);
} else {
// Remove all threaded UID's except the most recent of each thread
$threadedUids = [];
foreach ($aAllThreads as $aMap) {
unset($aMap[\array_key_last($aMap)]);
$threadedUids = \array_merge($threadedUids, $aMap);
}
$aUids = \array_diff($aUids, $threadedUids);
// Get all unseen
$aUnseenUIDs = $this->MessageListUnseen($oParams, $oInfo);
}
}
if ($aUids && \strlen($sSearch)) {
$aSearchedUids = $this->GetUids($oParams, $sSearch, $oInfo/*, $bUseSort*/);
if ($bUseThreads && !$oParams->iThreadUid) {
$matchingThreadUids = [];
foreach ($aAllThreads as $aMap) {
if (\array_intersect($aSearchedUids, $aMap)) {
$matchingThreadUids = \array_merge($matchingThreadUids, $aMap);
}
}
$aUids = \array_filter($aUids, function($iUid) use ($aSearchedUids, $matchingThreadUids) {
return \in_array($iUid, $aSearchedUids) || \in_array($iUid, $matchingThreadUids);
});
} else {
$aUids = \array_filter($aUids, function($iUid) use ($aSearchedUids) {
return \in_array($iUid, $aSearchedUids);
});
}
}
}
if (\count($aUids)) {
$oMessageCollection->totalEmails = \count($aUids);
$aUids = \array_slice($aUids, $oParams->iOffset, $oParams->iLimit);
$this->MessageListByRequestIndexOrUids($oMessageCollection, new SequenceSet($aUids), $aAllThreads, $aUnseenUIDs);
} }
return $oMessageCollection; return $oMessageCollection;

View file

@ -24,7 +24,8 @@ class MessageListParams
public bool public bool
$bUseSort = true, $bUseSort = true,
$bUseThreads = false, $bUseThreads = false,
$bHideDeleted = true; $bHideDeleted = true,
$bIgnoreLimit = false;
protected int protected int
$iOffset = 0, $iOffset = 0,

View file

@ -0,0 +1,45 @@
<?php
namespace SnappyMail;
abstract class Shutdown
{
private static
$actions = [],
$running = false;
final public function run() : void
{
if (!static::$running && \count(static::$actions)) {
static::$running = true;
\ini_set('display_errors', 0);
\ignore_user_abort(true);
# Flush all output buffers
if ($i = \ob_get_level()) {
while ($i-- && \ob_end_flush());
}
\flush();
if (\is_callable('fastcgi_finish_request')) {
// Special FPM/FastCGI (fpm-fcgi) function to finish request and
// flush all data while continuing to do something time-consuming.
\fastcgi_finish_request();
}
foreach (static::$actions as $action) {
try {
\call_user_func_array($action[0], $action[1]);
} catch (\Throwable $e) { } # skip
}
}
}
final public function add(callable $function, array $args = []) : void
{
if (!\count(static::$actions)) {
\register_shutdown_function('\\SnappyMail\\Shutdown::run');
}
static::$actions[] = [$function, $args];
}
}