Run full UID fetch in background when message_list_limit is set

This commit is contained in:
the-djmaze 2023-12-26 16:45:48 +01:00
parent ef850e37f7
commit 1a75a624cb
4 changed files with 125 additions and 86 deletions

View file

@ -435,6 +435,7 @@ class MailClient
return $aSerializedUids['ThreadsUids']; return $aSerializedUids['ThreadsUids'];
} }
} }
/*
// Idea to fetch all UID's in background // Idea to fetch all UID's in background
else if (!$bBackground) { else if (!$bBackground) {
$this->logWrite('Set MessageListThreadsMap() as background task ("'.$sFolderName.'" / '.$sSearch.')'); $this->logWrite('Set MessageListThreadsMap() as background task ("'.$sFolderName.'" / '.$sSearch.')');
@ -444,6 +445,7 @@ class MailClient
}, [$this, $oMessageCollection, $oCacher]); }, [$this, $oMessageCollection, $oCacher]);
return []; return [];
} }
*/
} }
$this->oImapClient->FolderExamine($sFolderName); $this->oImapClient->FolderExamine($sFolderName);
@ -529,59 +531,75 @@ class MailClient
* @throws \MailSo\Net\Exceptions\* * @throws \MailSo\Net\Exceptions\*
* @throws \MailSo\Imap\Exceptions\* * @throws \MailSo\Imap\Exceptions\*
*/ */
private function GetUids(MessageListParams $oParams, string $sSearch, private function GetUids(MessageListParams $oParams, FolderInformation $oInfo, bool $onlyCache = false) : array
FolderInformation $oInfo, bool $bUseSort = false) : array
{ {
$oCacher = $oParams->oCacher; $oCacher = $oParams->oCacher;
$sFolderName = $oParams->sFolderName; $sFolderName = $oParams->sFolderName;
$bUseSort = $bUseSort && $this->oImapClient->hasCapability('SORT'); $bUseSort = $oParams->bUseSort && $this->oImapClient->hasCapability('SORT');
$sSort = $bUseSort ? $oParams->sSort : ''; $aSortTypes = [];
/* TODO: Validate $sSort if ($bUseSort) {
ARRIVAL if ($oParams->sSort) {
Internal date and time of the message. This differs from the /* TODO: Validate $oParams->sSort
ON criteria in SEARCH, which uses just the internal date. * /(REVERSE\s+)?(ARRIVAL|CC|DATE|FROM|SIZE|SUBJECT|TO|DISPLAYFROM|DISPLAYTO)/
ARRIVAL
Internal date and time of the message. This differs from the
ON criteria in SEARCH, which uses just the internal date.
CC CC
[IMAP] addr-mailbox of the first "cc" address. [IMAP] addr-mailbox of the first "cc" address.
DATE DATE
Sent date and time, as described in section 2.2. Sent date and time, as described in section 2.2.
FROM FROM
[IMAP] addr-mailbox of the first "From" address. [IMAP] addr-mailbox of the first "From" address.
REVERSE REVERSE
Followed by another sort criterion, has the effect of that Followed by another sort criterion, has the effect of that
criterion but in reverse (descending) order. criterion but in reverse (descending) order.
Note: REVERSE only reverses a single criterion, and does not Note: REVERSE only reverses a single criterion, and does not
affect the implicit "sequence number" sort criterion if all affect the implicit "sequence number" sort criterion if all
other criteria are identical. Consequently, a sort of other criteria are identical. Consequently, a sort of
REVERSE SUBJECT is not the same as a reverse ordering of a REVERSE SUBJECT is not the same as a reverse ordering of a
SUBJECT sort. This can be avoided by use of additional SUBJECT sort. This can be avoided by use of additional
criteria, e.g., SUBJECT DATE vs. REVERSE SUBJECT REVERSE criteria, e.g., SUBJECT DATE vs. REVERSE SUBJECT REVERSE
DATE. In general, however, it's better (and faster, if the DATE. In general, however, it's better (and faster, if the
client has a "reverse current ordering" command) to reverse client has a "reverse current ordering" command) to reverse
the results in the client instead of issuing a new SORT. the results in the client instead of issuing a new SORT.
SIZE SIZE
Size of the message in octets. Size of the message in octets.
SUBJECT SUBJECT
Base subject text. Base subject text.
TO TO
[IMAP] addr-mailbox of the first "To" address. [IMAP] addr-mailbox of the first "To" address.
RFC 5957: RFC 5957:
$this->oImapClient->hasCapability('SORT=DISPLAY') $this->oImapClient->hasCapability('SORT=DISPLAY')
DISPLAYFROM, DISPLAYTO DISPLAYFROM, DISPLAYTO
*/ */
$aSortTypes[] = $oParams->sSort;
}
if (!\str_contains($oParams->sSort, 'DATE')) {
// Always also sort DATE descending when DATE is not defined
$aSortTypes[] = 'REVERSE DATE';
}
}
$oParams->sSort = \implode(' ', $aSortTypes);
$bUseCacheAfterSearch = $oCacher && $oCacher->IsInited(); $bUseCache = $oCacher && $oCacher->IsInited();
$sSearchCriterias = \MailSo\Imap\SearchCriterias::fromString($this->oImapClient, $sFolderName, $sSearch, $oParams->bHideDeleted, $bUseCacheAfterSearch); $sSearchCriterias = \MailSo\Imap\SearchCriterias::fromString(
$this->oImapClient,
$sFolderName,
$oParams->sSearch,
$oParams->bHideDeleted,
$bUseCache
);
// Disable? as there are many cases that change the result // Disable? as there are many cases that change the result
// $bUseCacheAfterSearch = false; // $bUseCache = false;
$bReturnUid = true; $bReturnUid = true;
if ($oParams->oSequenceSet) { if ($oParams->oSequenceSet) {
@ -591,12 +609,11 @@ class MailClient
$sSerializedHash = ''; $sSerializedHash = '';
$sSerializedLog = ''; $sSerializedLog = '';
if ($bUseCacheAfterSearch) { if ($bUseCache) {
$sSerializedHash = 'Get' $sSerializedHash = 'Get'
. ($bReturnUid ? 'UIDS/' : 'IDS/') . ($bReturnUid ? 'UIDS/' : 'IDS/')
. ($bUseSort ? 'S' . $sSort : 'N') . "{$oParams->sSort}/{$this->oImapClient->Hash()}/{$sFolderName}/{$sSearchCriterias}";
. "/{$this->oImapClient->Hash()}/{$sFolderName}/{$sSearchCriterias}"; $sSerializedLog = "\"{$sFolderName}\" / {$oParams->sSort} / {$sSearchCriterias}";
$sSerializedLog = "\"{$sFolderName}\" / {$sSort} / {$sSearchCriterias}";
$sSerialized = $oCacher->Get($sSerializedHash); $sSerialized = $oCacher->Get($sSerializedHash);
if (!empty($sSerialized)) { if (!empty($sSerialized)) {
@ -610,19 +627,14 @@ class MailClient
} }
} }
} }
if ($onlyCache) {
return [];
}
$this->oImapClient->FolderExamine($sFolderName); $this->oImapClient->FolderExamine($sFolderName);
$aResultUids = []; $aResultUids = [];
if ($bUseSort) { if ($bUseSort) {
$aSortTypes = [];
if ($sSort) {
$aSortTypes[] = $sSort;
}
if (false === \strpos($sSort, 'DATE')) {
// Always also sort DATE descending when DATE is not defined
$aSortTypes[] = 'REVERSE DATE';
}
// $this->oImapClient->hasCapability('ESORT') // $this->oImapClient->hasCapability('ESORT')
// $aResultUids = $this->oImapClient->MessageSimpleESort($aSortTypes, $sSearchCriterias)['ALL']; // $aResultUids = $this->oImapClient->MessageSimpleESort($aSortTypes, $sSearchCriterias)['ALL'];
$aResultUids = $this->oImapClient->MessageSimpleSort($aSortTypes, $sSearchCriterias, $bReturnUid); $aResultUids = $this->oImapClient->MessageSimpleSort($aSortTypes, $sSearchCriterias, $bReturnUid);
@ -632,7 +644,7 @@ class MailClient
$aResultUids = $this->oImapClient->MessageSimpleSearch($sSearchCriterias, $bReturnUid); $aResultUids = $this->oImapClient->MessageSimpleSearch($sSearchCriterias, $bReturnUid);
} }
if ($bUseCacheAfterSearch) { if ($bUseCache) {
$oCacher->Set($sSerializedHash, \json_encode(array( $oCacher->Set($sSerializedHash, \json_encode(array(
'FolderHash' => $oInfo->etag, 'FolderHash' => $oInfo->etag,
'Uids' => $aResultUids 'Uids' => $aResultUids
@ -641,6 +653,10 @@ class MailClient
$this->logWrite('Save Serialized '.($bReturnUid?'UIDS':'IDS').' to cache ('.$sSerializedLog.') [count:'.\count($aResultUids).']'); $this->logWrite('Save Serialized '.($bReturnUid?'UIDS':'IDS').' to cache ('.$sSerializedLog.') [count:'.\count($aResultUids).']');
} }
// $oSequenceSet = new SequenceSet($aResultUids, false);
// $oSequenceSet->UID = $bReturnUid;
// return $oSequenceSet;
return $aResultUids; return $aResultUids;
} }
@ -648,7 +664,7 @@ class MailClient
{ {
$oUnseenParams = new MessageListParams; $oUnseenParams = new MessageListParams;
$oUnseenParams->sFolderName = $oParams->sFolderName; $oUnseenParams->sFolderName = $oParams->sFolderName;
// $oUnseenParams->sSearch = $oParams->sSearch; $oUnseenParams->sSearch = 'unseen';
// $oUnseenParams->sSort = $oParams->sSort; // $oUnseenParams->sSort = $oParams->sSort;
$oUnseenParams->oCacher = $oParams->oCacher; $oUnseenParams->oCacher = $oParams->oCacher;
$oUnseenParams->bUseSort = false; // $oParams->bUseSort $oUnseenParams->bUseSort = false; // $oParams->bUseSort
@ -658,7 +674,7 @@ class MailClient
// $oUnseenParams->iLimit = $oParams->iLimit; // $oUnseenParams->iLimit = $oParams->iLimit;
// $oUnseenParams->iPrevUidNext = $oParams->iPrevUidNext; // $oUnseenParams->iPrevUidNext = $oParams->iPrevUidNext;
// $oUnseenParams->iThreadUid = $oParams->iThreadUid; // $oUnseenParams->iThreadUid = $oParams->iThreadUid;
return $this->GetUids($oUnseenParams, 'unseen', $oInfo); return $this->GetUids($oUnseenParams, $oInfo);
} }
/** /**
@ -688,14 +704,13 @@ class MailClient
$oMessageCollection->FolderInfo = $oInfo; $oMessageCollection->FolderInfo = $oInfo;
$oMessageCollection->totalEmails = $oInfo->MESSAGES; $oMessageCollection->totalEmails = $oInfo->MESSAGES;
$bUseThreads = $oParams->bUseThreads && $this->oImapClient->CapabilityValue('THREAD'); $oParams->bUseThreads = $oParams->bUseThreads && $this->oImapClient->CapabilityValue('THREAD');
// && ($this->oImapClient->hasCapability('THREAD=REFS') || $this->oImapClient->hasCapability('THREAD=REFERENCES') || $this->oImapClient->hasCapability('THREAD=ORDEREDSUBJECT')); // && ($this->oImapClient->hasCapability('THREAD=REFS') || $this->oImapClient->hasCapability('THREAD=REFERENCES') || $this->oImapClient->hasCapability('THREAD=ORDEREDSUBJECT'));
if ($oParams->iThreadUid && !$bUseThreads) { if ($oParams->iThreadUid && !$oParams->bUseThreads) {
throw new \InvalidArgumentException('THREAD not supported'); throw new \InvalidArgumentException('THREAD not supported');
} }
if (!$oInfo->MESSAGES) { if (!$oInfo->MESSAGES || $oParams->iOffset > $oInfo->MESSAGES) {
$this->logWrite('No messages in '.$oMessageCollection->FolderName);
return $oMessageCollection; return $oMessageCollection;
} }
@ -705,23 +720,41 @@ class MailClient
); );
} }
$bUseSort = $oParams->bUseSort || $oParams->sSort; $bUseSort = ($oParams->bUseSort || $oParams->sSort) && $this->oImapClient->hasCapability('SORT');
$oParams->bUseSort = $bUseSort;
$oParams->sSearch = $sSearch;
$aAllThreads = []; $aAllThreads = [];
$aUnseenUIDs = []; $aUnseenUIDs = [];
$aUids = []; $aUids = [];
$message_list_limit = $oParams->bIgnoreLimit ? 0 : $this->oImapClient->Settings->message_list_limit; $message_list_limit = $this->oImapClient->Settings->message_list_limit;
if (0 < $message_list_limit && $message_list_limit < $oInfo->MESSAGES) { if (100 > $message_list_limit || $message_list_limit > $oInfo->MESSAGES) {
/* $message_list_limit = 0;
// TODO: Idea to fetch all UID's in background }
// Must know what is cached so needs more thought // Idea to fetch all UID's in background
if ($oParams->oCacher && !$oParams->iOffset && !$oParams->iThreadUid && !\strlen($sSearch)) { $oAllParams = clone $oParams;
\SnappyMail\Shutdown::add(function($oMailClient, $oParams) { $oAllParams->sSearch = '';
$oParams->bIgnoreLimit = true; $oAllParams->oSequenceSet = null;
$oMailClient->MessageList($oParams); if ($message_list_limit && $message_list_limit < $oInfo->MESSAGES && !$oParams->iThreadUid
}, [$this, $oParams]); && $oParams->oCacher && $oParams->oCacher->IsInited()
) {
$aUids = $this->GetUids($oAllParams, $oInfo, true);
if ($aUids) {
$message_list_limit = 0;
$oMessageCollection->Sort = $oAllParams->sSort;
} else {
\SnappyMail\Shutdown::add(function($oMailClient, $oAllParams, $oInfo, $oMessageCollection) {
$oMailClient->GetUids($oAllParams, $oInfo);
if ($oAllParams->bUseThreads) {
$oMessageCollection->FolderInfo->MESSAGES = 0;
$oMailClient->MessageListThreadsMap($oMessageCollection, $oAllParams->oCacher, true);
}
}, [$this, $oAllParams, $oInfo, $oMessageCollection]);
} }
*/ }
if ($message_list_limit && $message_list_limit < $oInfo->MESSAGES && !$aUids) {
// 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'))) { // || (!$this->oImapClient->hasCapability('SORT') && !$this->oImapClient->CapabilityValue('THREAD'))) {
// Don't use THREAD for speed // Don't use THREAD for speed
@ -729,17 +762,15 @@ class MailClient
$this->logWrite('List optimization (count: '.$oInfo->MESSAGES.', limit:'.$message_list_limit.')'); $this->logWrite('List optimization (count: '.$oInfo->MESSAGES.', limit:'.$message_list_limit.')');
if (\strlen($sSearch)) { if (\strlen($sSearch)) {
// Don't use SORT for speed // Don't use SORT for speed
$aUids = $this->GetUids($oParams, $sSearch, $oInfo/*, $bUseSort*/); $oParams->bUseSort = false;
$aUids = $this->GetUids($oParams, $oInfo);
} else { } else {
$bUseSort = $this->oImapClient->hasCapability('SORT'); if ($bUseSort) {
if (2 > $oInfo->MESSAGES) {
$aRequestIndexes = \array_slice([1], $oParams->iOffset, 1);
} else if ($bUseSort) {
// Attempt to sort REVERSE DATE with a bigger range then $oParams->iLimit // Attempt to sort REVERSE DATE with a bigger range then $oParams->iLimit
$end = \min($oInfo->MESSAGES, \max(1, $oInfo->MESSAGES - $oParams->iOffset + $oParams->iLimit)); $end = \min($oInfo->MESSAGES, \max(1, $oInfo->MESSAGES - $oParams->iOffset + $oParams->iLimit));
$start = \max(1, $end - ($oParams->iLimit * 3) + 1); $start = \max(1, $end - ($oParams->iLimit * 3) + 1);
$oParams->oSequenceSet = new SequenceSet(\range($end, $start), false); $oParams->oSequenceSet = new SequenceSet(\range($end, $start), false);
$aRequestIndexes = $this->GetUids($oParams, '', $oInfo, $bUseSort); $aRequestIndexes = $this->GetUids($oParams, $oInfo);
// Attempt to get the correct $oParams->iLimit slice // Attempt to get the correct $oParams->iLimit slice
$aRequestIndexes = \array_slice($aRequestIndexes, $oParams->iOffset ? $oParams->iLimit : 0, $oParams->iLimit); $aRequestIndexes = \array_slice($aRequestIndexes, $oParams->iOffset ? $oParams->iLimit : 0, $oParams->iLimit);
} else { } else {
@ -750,12 +781,16 @@ class MailClient
} }
$this->MessageListByRequestIndexOrUids($oMessageCollection, new SequenceSet($aRequestIndexes, false)); $this->MessageListByRequestIndexOrUids($oMessageCollection, new SequenceSet($aRequestIndexes, false));
} }
$oMessageCollection->Sort = $oParams->sSort;
} else { } else {
$aUids = ($bUseThreads && $oParams->iThreadUid) if ($oParams->bUseThreads && $oParams->iThreadUid) {
? [$oParams->iThreadUid] $aUids = [$oParams->iThreadUid];
: $this->GetUids($oParams, '', $oInfo, $bUseSort); } else if (!$aUids) {
$aUids = $this->GetUids($oAllParams, $oInfo);
$oMessageCollection->Sort = $oAllParams->sSort;
}
if ($bUseThreads) { if ($oParams->bUseThreads) {
$aAllThreads = $this->MessageListThreadsMap($oMessageCollection, $oParams->oCacher); $aAllThreads = $this->MessageListThreadsMap($oMessageCollection, $oParams->oCacher);
$oMessageCollection->totalThreads = \count($aAllThreads); $oMessageCollection->totalThreads = \count($aAllThreads);
// $iThreadLimit = $this->oImapClient->Settings->thread_limit; // $iThreadLimit = $this->oImapClient->Settings->thread_limit;
@ -784,8 +819,9 @@ class MailClient
} }
if ($aUids && \strlen($sSearch)) { if ($aUids && \strlen($sSearch)) {
$aSearchedUids = $this->GetUids($oParams, $sSearch, $oInfo/*, $bUseSort*/); $oParams->bUseSort = false;
if ($bUseThreads && !$oParams->iThreadUid) { $aSearchedUids = $this->GetUids($oParams, $oInfo);
if ($oParams->bUseThreads && !$oParams->iThreadUid) {
$matchingThreadUids = []; $matchingThreadUids = [];
foreach ($aAllThreads as $aMap) { foreach ($aAllThreads as $aMap) {
if (\array_intersect($aSearchedUids, $aMap)) { if (\array_intersect($aSearchedUids, $aMap)) {

View file

@ -32,6 +32,8 @@ class MessageCollection extends \MailSo\Base\Collection
public string $Search = ''; public string $Search = '';
public string $Sort = '';
public int $ThreadUid = 0; public int $ThreadUid = 0;
// MailSo\Imap\FolderInformation // MailSo\Imap\FolderInformation
@ -57,7 +59,7 @@ class MessageCollection extends \MailSo\Base\Collection
#[\ReturnTypeWillChange] #[\ReturnTypeWillChange]
public function jsonSerialize() public function jsonSerialize()
{ {
return array_merge(parent::jsonSerialize(), array( return \array_merge(parent::jsonSerialize(), array(
'totalEmails' => $this->totalEmails, 'totalEmails' => $this->totalEmails,
'totalThreads' => $this->totalThreads, 'totalThreads' => $this->totalThreads,
'threadUid' => $this->ThreadUid, 'threadUid' => $this->ThreadUid,
@ -66,6 +68,7 @@ class MessageCollection extends \MailSo\Base\Collection
'offset' => $this->Offset, 'offset' => $this->Offset,
'limit' => $this->Limit, 'limit' => $this->Limit,
'search' => $this->Search, 'search' => $this->Search,
'sort' => $this->Sort,
'limited' => $this->Limited, 'limited' => $this->Limited,
'folder' => $this->FolderInfo 'folder' => $this->FolderInfo
)); ));

View file

@ -24,8 +24,7 @@ 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,
@ -61,7 +60,7 @@ class MessageListParams
$this->iLimit, $this->iLimit,
$this->bHideDeleted ? '1' : '0', $this->bHideDeleted ? '1' : '0',
$this->sSearch, $this->sSearch,
$this->bUseSort ? $this->sSort : '', $this->bUseSort ? $this->sSort : '0',
$this->bUseThreads ? $this->iThreadUid : '', $this->bUseThreads ? $this->iThreadUid : '',
$this->iPrevUidNext $this->iPrevUidNext
])); ]));

View file

@ -77,6 +77,7 @@ trait Messages
$oParams->oCacher = $this->Cacher($oAccount); $oParams->oCacher = $this->Cacher($oAccount);
} }
// $oParams->bUseSort = $this->ImapClient->hasCapability('SORT');
$oParams->bUseSort = true; $oParams->bUseSort = true;
$oSettingsLocal = $this->SettingsProvider(true)->Load($oAccount); $oSettingsLocal = $this->SettingsProvider(true)->Load($oAccount);