Offload server CPU to client when fetching folder list

This commit is contained in:
djmaze 2021-12-08 14:08:25 +01:00
parent 32712415ef
commit c8e4d589cb
8 changed files with 59 additions and 197 deletions

View file

@ -35,11 +35,6 @@ class Folder implements \JsonSerializable
*/
private $oImapFolder;
/**
* @var \MailSo\Mail\FolderCollection
*/
private $oSubFolders = null;
/**
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
*/
@ -85,33 +80,6 @@ class Folder implements \JsonSerializable
return $this->oImapFolder->FlagsLowerCase();
}
public function SubFolders(bool $bCreateIfNull = false) : ?\MailSo\Mail\FolderCollection
{
if ($bCreateIfNull && !$this->oSubFolders)
{
$this->oSubFolders = new FolderCollection;
}
return $this->oSubFolders;
}
public function HasSubFolders() : bool
{
return $this->oSubFolders && 0 < $this->oSubFolders->Count();
}
public function HasVisibleSubFolders() : bool
{
if ($this->oSubFolders) {
foreach ($this->oSubFolders as $oFolder) {
if ($oFolder->IsSubscribed()) {
return true;
}
}
}
return false;
}
public function IsSubscribed() : bool
{
return $this->bSubscribed;
@ -254,7 +222,6 @@ class Folder implements \JsonSerializable
'Name' => $this->Name(),
'FullName' => $this->FullName(),
'Delimiter' => (string) $this->Delimiter(),
// 'HasVisibleSubFolders' => $this->HasVisibleSubFolders(),
'Subscribed' => $this->bSubscribed,
'Exists' => $this->bExists,
'Selectable' => $this->IsSelectable(),

View file

@ -30,48 +30,9 @@ class FolderCollection extends \MailSo\Base\Collection
parent::append($oFolder, $bToTop);
}
public function GetByFullName(string $sFullName) : ?Folder
{
foreach ($this as $oFolder) {
if ($oFolder->FullName() === $sFullName) {
return $oFolder;
}
if ($oFolder->HasSubFolders()) {
$mResult = $oFolder->SubFolders(true)->GetByFullName($sFullName);
if ($mResult) {
return $mResult;
}
}
}
return null;
}
public function FindDelimiter() : string
{
$sDelimiter = '/';
$oFolder = $this->GetByFullName('INBOX');
if (!$oFolder && isset($this[0]))
{
$oFolder = $this[0];
}
$oFolder = $this['INBOX'] ?? $this[0] ?? null;
return $oFolder ? $oFolder->Delimiter() : '/';
}
public function AddWithPositionSearch(Folder $oMailFolder) : void
{
foreach ($this as $oItemFolder)
{
if (\str_starts_with($oMailFolder->FullName(), $oItemFolder->FullName().$oItemFolder->Delimiter()))
{
$oItemFolder->SubFolders(true)->AddWithPositionSearch($oMailFolder);
return;
}
}
$this->append($oMailFolder);
}
}

View file

@ -1233,75 +1233,40 @@ class MailClient
$oFolderCollection->Optimized = 10 < $iOptimizationLimit && \count($aFolders) > $iOptimizationLimit;
$sINBOX = 'INBOX';
$aSortedByLenImapFolders = array();
foreach ($aFolders as /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder)
{
foreach ($aFolders as $sFullName => /* @var $oImapFolder \MailSo\Imap\Folder */ $oImapFolder) {
$oMailFolder = new Folder($oImapFolder,
($bUseListSubscribeStatus && (null === $aImapSubscribedFoldersHelper || \in_array($oImapFolder->FullName(), $aImapSubscribedFoldersHelper)))
($bUseListSubscribeStatus && (null === $aImapSubscribedFoldersHelper || \in_array($sFullName, $aImapSubscribedFoldersHelper)))
|| $oImapFolder->IsInbox()
);
if ($oImapFolder->IsInbox()) {
$sINBOX = $oMailFolder->FullName();
$sINBOX = $sFullName;
}
$aSortedByLenImapFolders[$oMailFolder->FullName()] = $oMailFolder;
}
$aFolders[$sFullName] = $oMailFolder;
// Add NonExistent folders
$aAddedFolders = array();
foreach ($aSortedByLenImapFolders as /* @var $oMailFolder Folder */ $oMailFolder)
{
// Add NonExistent folders
$sDelimiter = $oMailFolder->Delimiter();
$aFolderExplode = \explode($sDelimiter, $oMailFolder->FullName());
if (1 < \count($aFolderExplode))
{
\array_pop($aFolderExplode);
$sNonExistentFolderFullName = '';
foreach ($aFolderExplode as $sFolderExplodeItem)
{
$sNonExistentFolderFullName .= \strlen($sNonExistentFolderFullName)
? $sDelimiter.$sFolderExplodeItem : $sFolderExplodeItem;
if (!isset($aSortedByLenImapFolders[$sNonExistentFolderFullName]))
$aFolderExplode = \explode($sDelimiter, $sFullName);
\array_pop($aFolderExplode);
while ($aFolderExplode) {
$sNonExistentFolderFullName = \implode($sDelimiter, $aFolderExplode);
if (!isset($aFolders[$sNonExistentFolderFullName])) {
try
{
try
{
$aAddedFolders[$sNonExistentFolderFullName] =
Folder::NewNonExistentInstance($sNonExistentFolderFullName, $sDelimiter);
}
catch (\Throwable $oExc)
{
unset($oExc);
}
$aFolders[$sNonExistentFolderFullName] =
Folder::NewNonExistentInstance($sNonExistentFolderFullName, $sDelimiter);
}
catch (\Throwable $oExc)
{
unset($oExc);
}
}
\array_pop($aFolderExplode);
}
}
$aSortedByLenImapFolders = \array_merge($aSortedByLenImapFolders, $aAddedFolders);
unset($aAddedFolders);
$oFolderCollection->exchangeArray(\array_values($aFolders));
// Make sure the inbox is the first in list when sorted
if (isset($aSortedByLenImapFolders[$sINBOX])) {
$aSortedByLenImapFolders["\x00".$sINBOX] = $aSortedByLenImapFolders[$sINBOX];
unset($aSortedByLenImapFolders[$sINBOX]);
}
/*
// TODO: use active language
$collator = new \Collator('en_US');
\uksort($aSortedByLenImapFolders, static fn($a, $b) => $collator->compare($a, $b));
*/
\uksort($aSortedByLenImapFolders, 'strnatcasecmp');
foreach ($aSortedByLenImapFolders as $oMailFolder)
{
$oFolderCollection->AddWithPositionSearch($oMailFolder);
}
$oFolderCollection->TotalCount = \count($aSortedByLenImapFolders);
unset($aSortedByLenImapFolders);
$oFolderCollection->TotalCount = \count($aFolders);
return $oFolderCollection;
}

View file

@ -48,7 +48,7 @@ trait Folders
});
}
if ($this->Config()->Get('labs', 'autocreate_system_folders', true))
if ($this->Config()->Get('labs', 'autocreate_system_folders', false))
{
$bDoItAgain = false;
@ -110,16 +110,17 @@ trait Folders
}
$sFullNameToCheck = $mFolderNameToCreate;
if (\strlen(\trim($sParent)))
if (\strlen($sParent))
{
$sFullNameToCheck = $sParent.$sDelimiter.$sFullNameToCheck;
}
if (!$oFolderCollection->GetByFullName($sFullNameToCheck))
if (!isset($oFolderCollection[$sFullNameToCheck]))
{
try
{
$this->MailClient()->FolderCreate($mFolderNameToCreate, $sParent, true, $sDelimiter);
$bDoItAgain = true;
}
catch (\Throwable $oException)
{
@ -172,7 +173,6 @@ trait Folders
'quotaUsage' => $aQuota ? $aQuota[0] * 1024 : null,
'quotaLimit' => $aQuota ? $aQuota[1] * 1024 : null,
'Namespace' => $sNamespace,
'FoldersHash' => \md5(\implode("\x0", $this->recFoldersNames($oFolderCollection))),
'IsThreadsSupported' => $this->MailClient()->IsThreadsSupported(),
'Optimized' => $oFolderCollection->Optimized,
'CountRec' => $oFolderCollection->TotalCount,
@ -470,27 +470,6 @@ trait Folders
$this->SettingsProvider(true)->Save($oAccount, $oSettingsLocal));
}
private function recFoldersNames(\MailSo\Mail\FolderCollection $oFolders) : array
{
$aResult = array();
if ($oFolders)
{
foreach ($oFolders as $oFolder)
{
$aResult[] = $oFolder->FullName()."|".
implode("|", $oFolder->FlagsLowerCase()).($oFolder->IsSubscribed() ? '1' : '0');
$oSub = $oFolder->SubFolders();
if ($oSub && 0 < $oSub->Count())
{
$aResult = \array_merge($aResult, $this->recFoldersNames($oSub));
}
}
}
return $aResult;
}
private function recFoldersTypes(\RainLoop\Model\Account $oAccount, \MailSo\Mail\FolderCollection $oFolders, array &$aResult, bool $bListFolderTypes = true) : void
{
if ($oFolders->Count())
@ -512,15 +491,6 @@ trait Folders
$aResult[$iFolderType] = $oFolder->FullName();
}
}
foreach ($oFolders as $oFolder)
{
$oSub = $oFolder->SubFolders();
if ($oSub && $oSub->Count())
{
$this->recFoldersTypes($oAccount, $oSub, $aResult, true);
}
}
}
$aMap = $this->systemFoldersNames($oAccount);
@ -545,15 +515,6 @@ trait Folders
}
}
}
foreach ($oFolders as $oFolder)
{
$oSub = $oFolder->SubFolders();
if ($oSub && $oSub->Count())
{
$this->recFoldersTypes($oAccount, $oSub, $aResult, false);
}
}
}
}

View file

@ -378,7 +378,6 @@ trait Response
array(
'Checkable' => \in_array($mResponse->FullName(), $this->aCheckableFolder),
'Extended' => $aExtended,
'SubFolders' => $this->responseObject($mResponse->SubFolders(), $sParent, $aParameters)
)
);
}