New thread controller

This commit is contained in:
RainLoop Team 2015-03-06 04:42:40 +04:00
parent 9dbf77f942
commit b6ca9e357e
20 changed files with 922 additions and 595 deletions

View file

@ -49,7 +49,7 @@ class Config
/**
* @var int
*/
public static $LargeThreadLimit = 100;
public static $LargeThreadLimit = 50;
/**
* @var bool

View file

@ -698,6 +698,18 @@ class MailClient
}
}
/**
* @return string
*/
public function GenerateImapClientHash()
{
return \md5('ImapClientHash/'.
$this->oImapClient->GetLogginedUser().'@'.
$this->oImapClient->GetConnectedHost().':'.
$this->oImapClient->GetConnectedPort()
);
}
/**
* @param string $sFolder
* @param int $iCount
@ -706,10 +718,12 @@ class MailClient
*
* @return string
*/
public static function GenerateHash($sFolder, $iCount, $iUnseenCount, $sUidNext)
public function GenerateFolderHash($sFolder, $iCount, $iUnseenCount, $sUidNext)
{
$iUnseenCount = 0; // unneccessery
return \md5($sFolder.'-'.$iCount.'-'.$iUnseenCount.'-'.$sUidNext);
return \md5('FolderHash/'.$sFolder.'-'.$iCount.'-'.$iUnseenCount.'-'.$sUidNext.'-'.
$this->GenerateImapClientHash()
);
}
/**
@ -837,7 +851,7 @@ class MailClient
$aResult = array(
'Folder' => $sFolderName,
'Hash' => self::GenerateHash($sFolderName, $iCount, $iUnseenCount, $sUidNext),
'Hash' => $this->GenerateFolderHash($sFolderName, $iCount, $iUnseenCount, $sUidNext),
'MessageCount' => $iCount,
'MessageUnseenCount' => $iUnseenCount,
'UidNext' => $sUidNext,
@ -866,7 +880,7 @@ class MailClient
$this->initFolderValues($sFolderName, $iCount, $iUnseenCount, $sUidNext);
return self::GenerateHash($sFolderName, $iCount, $iUnseenCount, $sUidNext);
return $this->GenerateFolderHash($sFolderName, $iCount, $iUnseenCount, $sUidNext);
}
/**
@ -1410,7 +1424,8 @@ class MailClient
* @param string $sFolderHash
* @param array $aIndexOrUids
* @param \MailSo\Cache\CacheClient $oCacher
* @param int $iThreadLimit = 100
* @param int $iThreadLimit = 50
* @param bool $bCacheOnly = false
*
* @return array
*
@ -1418,7 +1433,7 @@ class MailClient
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Imap\Exceptions\Exception
*/
public function MessageListThreadsMap($sFolderName, $sFolderHash, $aIndexOrUids, $oCacher, $iThreadLimit = 100)
public function MessageListThreadsMap($sFolderName, $sFolderHash, $aIndexOrUids, $oCacher, $iThreadLimit = 50, $bCacheOnly = false)
{
$iThreadLimit = \is_int($iThreadLimit) && 0 < $iThreadLimit ? $iThreadLimit : 0;
@ -1438,30 +1453,36 @@ class MailClient
if ($oCacher && $oCacher->IsInited())
{
$sSerializedHash =
$sSerializedHashKey =
'ThreadsMapSorted/'.$sSearchHash.'/'.
'Limit='.$iThreadLimit.'/'.
$this->oImapClient->GetLogginedUser().'@'.
$this->oImapClient->GetConnectedHost().':'.
$this->oImapClient->GetConnectedPort().'/'.
$sFolderName.'/'.$sFolderHash;
'Limit='.$iThreadLimit.'/'.$sFolderName.'/'.$sFolderHash;
$sSerializedUids = $oCacher->Get($sSerializedHash);
if ($this->oLogger)
{
$this->oLogger->Write($sSerializedHashKey);
}
$sSerializedUids = $oCacher->Get($sSerializedHashKey);
if (!empty($sSerializedUids))
{
$aSerializedUids = @\unserialize($sSerializedUids);
if (is_array($aSerializedUids))
$aSerializedUids = @\json_decode($sSerializedUids, true);
if (isset($aSerializedUids['ThreadsUids']) && \is_array($aSerializedUids['ThreadsUids']))
{
if ($this->oLogger)
{
$this->oLogger->Write('Get Serialized Thread UIDS from cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aSerializedUids).']');
$this->oLogger->Write('Get Serialized Thread UIDS from cache ("'.$sFolderName.'" / '.$sSearchHash.') [count:'.\count($aSerializedUids['ThreadsUids']).']');
}
return $aSerializedUids;
return $aSerializedUids['ThreadsUids'];
}
}
}
if ($bCacheOnly)
{
return null;
}
$this->oImapClient->FolderExamine($sFolderName);
$aThreadUids = array();
@ -1471,6 +1492,7 @@ class MailClient
}
catch (\MailSo\Imap\Exceptions\RuntimeException $oException)
{
unset($oException);
$aThreadUids = array();
}
@ -1582,9 +1604,11 @@ class MailClient
$aResult = $aLastResult;
unset($aLastResult);
if ($oCacher && $oCacher->IsInited() && !empty($sSerializedHash))
if ($oCacher && $oCacher->IsInited() && !empty($sSerializedHashKey))
{
$oCacher->Set($sSerializedHash, serialize($aResult));
$oCacher->Set($sSerializedHashKey, @\json_encode(array(
'ThreadsUids' => $aResult
)));
if ($this->oLogger)
{
@ -1668,8 +1692,8 @@ class MailClient
private function getSearchUidsResult($sSearch, $sFolderName, $sFolderHash,
$bUseSortIfSupported = true, $bUseESearchOrESortRequest = false, $oCacher = null)
{
$bUidsFromCacher = false;
$aResultUids = false;
$bUidsFromCacher = false;
$bUseCacheAfterSearch = true;
$sSerializedHash = '';
@ -1680,23 +1704,21 @@ class MailClient
$sSearchCriterias = $this->getImapSearchCriterias($sSearch, 0, $bUseCacheAfterSearch);
if ($bUseCacheAfterSearch && $oCacher && $oCacher->IsInited())
{
$sSerializedHash =
$sSerializedHash = 'SearchSortUids/'.
($bUseSortIfSupported ? 'S': 'N').'/'.
$this->oImapClient->GetLogginedUser().'@'.
$this->oImapClient->GetConnectedHost().':'.
$this->oImapClient->GetConnectedPort().'/'.
$sFolderName.'/'.
$sSearchCriterias;
$this->GenerateImapClientHash().'/'.
$sFolderName.'/'.$sSearchCriterias;
$sSerializedLog = '"'.$sFolderName.'" / '.$sSearchCriterias.'';
$sSerialized = $oCacher->Get($sSerializedHash);
if (!empty($sSerialized))
{
$aSerialized = @\unserialize($sSerialized);
$aSerialized = @\json_decode($sSerialized, true);
if (\is_array($aSerialized) && isset($aSerialized['FolderHash'], $aSerialized['Uids']) &&
\is_array($aSerialized['Uids']) &&
($sFolderHash === $aSerialized['FolderHash']))
$sFolderHash === $aSerialized['FolderHash'] &&
\is_array($aSerialized['Uids'])
)
{
if ($this->oLogger)
{
@ -1779,7 +1801,7 @@ class MailClient
if (!$bUidsFromCacher && $bUseCacheAfterSearch && \is_array($aResultUids) && $oCacher && $oCacher->IsInited() && 0 < \strlen($sSerializedHash))
{
$oCacher->Set($sSerializedHash, \serialize(array(
$oCacher->Set($sSerializedHash, @\json_encode(array(
'FolderHash' => $sFolderHash,
'Uids' => $aResultUids
)));
@ -1794,6 +1816,54 @@ class MailClient
return $aResultUids;
}
/**
* @param string $sFolderName
* @param string $sFolderHash
* @param string $sUid
* @param \MailSo\Cache\CacheClient|null $oCacher = null
*
* @return array
*/
public function MessageThreadUidsFromCache($sFolderName, $sFolderHash, $sUid, $oCacher = null)
{
$aResult = array();
if (0 < \strlen($sFolderName) && 0 < \strlen($sFolderHash) && 0 < \strlen($sUid) && $oCacher && $oCacher->IsInited())
{
$mThreads = $this->MessageListThreadsMap($sFolderName, $sFolderHash, array(), $oCacher,
\MailSo\Config::$LargeThreadLimit, true);
if (\is_array($mThreads))
{
$iUid = (int) $sUid;
foreach ($mThreads as $iSubUid => $aSubUids)
{
if ($iUid === $iSubUid)
{
$aResult = $aSubUids;
if (!\is_array($aResult))
{
$aResult = array();
}
\array_unshift($aResult, $iSubUid);
break;
}
else if (\is_array($aSubUids))
{
if (\in_array($iUid, $aSubUids))
{
$aResult = $aSubUids;
\array_unshift($aResult, $iSubUid);
break;
}
}
}
}
}
return \array_map('trim', $aResult);
}
/**
* @param string $sFolderName
* @param int $iOffset = 0
@ -1803,7 +1873,6 @@ class MailClient
* @param \MailSo\Cache\CacheClient|null $oCacher = null
* @param bool $bUseSortIfSupported = false
* @param bool $bUseThreadSortIfSupported = false
* @param array $aExpandedThreadsUids = array()
* @param bool $bUseESearchOrESortRequest = false
*
* @return \MailSo\Mail\MessageCollection
@ -1812,9 +1881,8 @@ class MailClient
* @throws \MailSo\Net\Exceptions\Exception
* @throws \MailSo\Imap\Exceptions\Exception
*/
public function MessageList($sFolderName, $iOffset = 0, $iLimit = 10, $sSearch = '', $sPrevUidNext = '',
$oCacher = null, $bUseSortIfSupported = false, $bUseThreadSortIfSupported = false,
$aExpandedThreadsUids = array(), $bUseESearchOrESortRequest = false)
public function MessageList($sFolderName, $iOffset = 0, $iLimit = 10, $sSearch = '', $sPrevUidNext = '', $oCacher = null,
$bUseSortIfSupported = false, $bUseThreadSortIfSupported = false, $bUseESearchOrESortRequest = false)
{
$sSearch = \trim($sSearch);
if (!\MailSo\Base\Validator::RangeInt($iOffset, 0) ||
@ -1831,8 +1899,6 @@ class MailClient
$oMessageCollection->Limit = $iLimit;
$oMessageCollection->Search = $sSearch;
$aLastCollapsedThreadUids = array();
$aThreads = array();
$iMessageCount = 0;
@ -1853,7 +1919,7 @@ class MailClient
$this->initFolderValues($sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext);
$iMessageCount = $iMessageRealCount;
$oMessageCollection->FolderHash = self::GenerateHash($sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext);
$oMessageCollection->FolderHash = $this->GenerateFolderHash($sFolderName, $iMessageRealCount, $iMessageUnseenCount, $sUidNext);
$oMessageCollection->UidNext = $sUidNext;
$oMessageCollection->NewMessages = $this->getFolderNextMessageInformation($sFolderName, $sPrevUidNext, $sUidNext);
@ -1889,11 +1955,9 @@ class MailClient
$oMessageCollection->FolderName, $oMessageCollection->FolderHash,
$bUseSortIfSupported, $bUseESearchOrESortRequest, $oCacher);
$aThreads = $this->MessageListThreadsMap($oMessageCollection->FolderName, $oMessageCollection->FolderHash, $aIndexOrUids,
$oCacher, \MailSo\Config::$LargeThreadLimit);
$aExpandedThreadsUids = \is_array($aExpandedThreadsUids) ? $aExpandedThreadsUids : array();
$bWatchExpanded = 0 < \count($aExpandedThreadsUids);
$aThreads = $this->MessageListThreadsMap(
$oMessageCollection->FolderName, $oMessageCollection->FolderHash,
$aIndexOrUids, $oCacher, \MailSo\Config::$LargeThreadLimit);
$aNewIndexOrUids = array();
foreach ($aIndexOrUids as $iUid)
@ -1901,21 +1965,6 @@ class MailClient
if (isset($aThreads[$iUid]))
{
$aNewIndexOrUids[] = $iUid;
if (\is_array($aThreads[$iUid]))
{
if ($bWatchExpanded && \in_array($iUid, $aExpandedThreadsUids))
{
$aSubArray = $aThreads[$iUid];
foreach ($aSubArray as $iSubRootUid)
{
$aNewIndexOrUids[] = $iSubRootUid;
}
}
else
{
$aLastCollapsedThreadUids[] = $iUid;
}
}
}
}
@ -1966,38 +2015,20 @@ class MailClient
}
}
$aLastCollapsedThreadUidsForPage = array();
if (!$bSearch && $bUseThreadSortIfSupported && 0 < \count($aThreads))
{
$oMessageCollection->ForeachList(function (/* @var $oMessage \MailSo\Mail\Message */ $oMessage) use (
$aThreads, $aLastCollapsedThreadUids, &$aLastCollapsedThreadUidsForPage)
{
$iUid = $oMessage->Uid();
if (\in_array($iUid, $aLastCollapsedThreadUids))
{
$aLastCollapsedThreadUidsForPage[] = $iUid;
}
$oMessageCollection->ForeachList(function (/* @var $oMessage \MailSo\Mail\Message */ $oMessage) use ($aThreads) {
$iUid = $oMessage->Uid();
if (isset($aThreads[$iUid]) && \is_array($aThreads[$iUid]) && 0 < \count($aThreads[$iUid]))
{
$oMessage->SetThreads($aThreads[$iUid]);
$oMessage->SetThreadsLen(\count($aThreads[$iUid]));
}
else if (!isset($aThreads[$iUid]))
{
foreach ($aThreads as $iKeyUid => $mSubItem)
{
if (\is_array($mSubItem) && \in_array($iUid, $mSubItem))
{
$oMessage->SetParentThread($iKeyUid);
$oMessage->SetThreadsLen(\count($mSubItem));
}
}
$aSubThreads = $aThreads[$iUid];
\array_unshift($aSubThreads, $iUid);
$oMessage->SetThreads(\array_map('trim', $aSubThreads));
unset($aSubThreads);
}
});
$oMessageCollection->LastCollapsedThreadUids = $aLastCollapsedThreadUidsForPage;
}
return $oMessageCollection;

View file

@ -162,16 +162,6 @@ class Message
*/
private $aThreads;
/**
* @var int
*/
private $iParentThread;
/**
* @var int
*/
private $iThreadsLen;
/**
* @var bool
*/
@ -240,8 +230,6 @@ class Message
$this->sReadReceipt = '';
$this->aThreads = array();
$this->iThreadsLen = 0;
$this->iParentThread = 0;
$this->bTextPartIsTrimmed = false;
@ -542,38 +530,6 @@ class Message
$this->aThreads = \is_array($aThreads) ? $aThreads : array();
}
/**
* @return int
*/
public function ThreadsLen()
{
return $this->iThreadsLen;
}
/**
* @param int $iThreadsLen
*/
public function SetThreadsLen($iThreadsLen)
{
$this->iThreadsLen = $iThreadsLen;
}
/**
* @return int
*/
public function ParentThread()
{
return $this->iParentThread;
}
/**
* @param int $iParentThread
*/
public function SetParentThread($iParentThread)
{
$this->iParentThread = $iParentThread;
}
/**
* @return boole
*/
@ -664,7 +620,8 @@ class Message
$this->oDeliveredTo = $oHeaders->GetAsEmailCollection(\MailSo\Mime\Enumerations\Header::DELIVERED_TO, $bCharsetAutoDetect);
$this->sInReplyTo = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::IN_REPLY_TO);
$this->sReferences = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::REFERENCES);
$this->sReferences = \trim(\preg_replace('/[\s]+/', ' ',
$oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::REFERENCES)));
$sHeaderDate = $oHeaders->ValueByName(\MailSo\Mime\Enumerations\Header::DATE);
$this->sHeaderDate = $sHeaderDate;

View file

@ -256,7 +256,8 @@ class Message
*/
public function SetReferences($sReferences)
{
$this->aHeadersValue[\MailSo\Mime\Enumerations\Header::REFERENCES] = $sReferences;
$this->aHeadersValue[\MailSo\Mime\Enumerations\Header::REFERENCES] =
\trim(\preg_replace('/[\s]+/', ' ', $sReferences));
return $this;
}

View file

@ -5363,6 +5363,45 @@ class Actions
return $this->DefaultResponse(__FUNCTION__, $aResult);
}
/**
* @return array
*
* @throws \MailSo\Base\Exceptions\Exception
*/
public function DoMessageThreadsFromCache()
{
$sFolder = $this->GetActionParam('Folder', '');
$sFolderHash = $this->GetActionParam('FolderHash', '');
$sUid = (string) $this->GetActionParam('Uid', '');
if (0 === \strlen($sFolder) || 0 === \strlen($sUid))
{
throw new \RainLoop\Exceptions\ClientException(\RainLoop\Notifications::InvalidInputArgument);
}
$aResult = array(
'Folder' => $sFolder,
'Uid' => $sUid,
'FolderHash' => $sFolderHash,
'ThreadUids' => null
);
$oCache = $this->cacherForUids();
if ($oCache && $this->Config()->Get('labs', 'use_imap_thread', false))
{
$aThreadUids = $this->MailClient()->MessageThreadUidsFromCache(
$sFolder, $sFolderHash, $sUid, $oCache
);
if (\is_array($aThreadUids) && 1 < \count($aThreadUids))
{
$aResult['ThreadUids'] = $aThreadUids;
}
}
return $this->DefaultResponse(__FUNCTION__, $aResult);
}
/**
* @return array
*
@ -5379,7 +5418,6 @@ class Actions
$sSearch = '';
$sUidNext = '';
$bUseThreads = false;
$sExpandedThreadUid = '';
$sRawKey = $this->GetActionParam('RawKey', '');
$aValues = $this->getDecodedClientRawKeyValue($sRawKey, 9);
@ -5392,7 +5430,6 @@ class Actions
$sSearch = (string) $aValues[3];
$sUidNext = (string) $aValues[6];
$bUseThreads = (bool) $aValues[7];
$sExpandedThreadUid = (string) $aValues[8];
$this->verifyCacheByKey($sRawKey);
}
@ -5404,7 +5441,6 @@ class Actions
$sSearch = $this->GetActionParam('Search', '');
$sUidNext = $this->GetActionParam('UidNext', '');
$bUseThreads = '1' === (string) $this->GetActionParam('UseThreads', '0');
$sExpandedThreadUid = (string) $this->GetActionParam('ExpandedThreadUid', '');
}
if (0 === strlen($sFolder))
@ -5419,29 +5455,13 @@ class Actions
if (!$this->Config()->Get('labs', 'use_imap_thread', false))
{
$bUseThreads = false;
$sExpandedThreadUid = '';
}
$aExpandedThreadUid = array();
if (0 < \strlen($sExpandedThreadUid))
{
$aExpandedThreadUid = \explode(',', $sExpandedThreadUid);
$aExpandedThreadUid = \array_map(function ($sValue) {
$sValue = \trim($sValue);
return \is_numeric($sValue) ? (int) $sValue : 0;
}, $aExpandedThreadUid);
$aExpandedThreadUid = \array_filter($aExpandedThreadUid, function ($iValue) {
return 0 < $iValue;
});
}
$oMessageList = $this->MailClient()->MessageList(
$sFolder, $iOffset, $iLimit, $sSearch, $sUidNext,
$this->cacherForUids(),
!!$this->Config()->Get('labs', 'use_imap_sort', false),
$bUseThreads, $aExpandedThreadUid,
$bUseThreads,
!!$this->Config()->Get('labs', 'use_imap_esearch_esort', false)
);
}
@ -8875,8 +8895,6 @@ class Actions
'DeliveredTo' => $this->responseObject($mResponse->DeliveredTo(), $sParent, $aParameters),
'Priority' => $mResponse->Priority(),
'Threads' => $mResponse->Threads(),
'ThreadsLen' => $mResponse->ThreadsLen(),
'ParentThread' => $mResponse->ParentThread(),
'Sensitivity' => $mResponse->Sensitivity(),
'ExternalProxy' => false,
'ReadReceipt' => ''
@ -9149,7 +9167,7 @@ class Actions
'MessageCount' => (int) $mStatus['MESSAGES'],
'MessageUnseenCount' => (int) $mStatus['UNSEEN'],
'UidNext' => (string) $mStatus['UIDNEXT'],
'Hash' => \MailSo\Mail\MailClient::GenerateHash(
'Hash' => $this->MailClient()->GenerateFolderHash(
$mResponse->FullNameRaw(), $mStatus['MESSAGES'], $mStatus['UNSEEN'], $mStatus['UIDNEXT'])
);
}
@ -9179,7 +9197,7 @@ class Actions
'FolderHash' => $mResponse->FolderHash,
'UidNext' => $mResponse->UidNext,
'NewMessages' => $this->responseObject($mResponse->NewMessages),
'LastCollapsedThreadUids' => $mResponse->LastCollapsedThreadUids,
// 'LastCollapsedThreadUids' => $mResponse->LastCollapsedThreadUids,
'Offset' => $mResponse->Offset,
'Limit' => $mResponse->Limit,
'Search' => $mResponse->Search

View file

@ -92,7 +92,7 @@ class Api
(int) \RainLoop\Api::Config()->Get('labs', 'imap_message_list_date_filter', 0);
\MailSo\Config::$LargeThreadLimit =
(int) \RainLoop\Api::Config()->Get('labs', 'imap_large_thread_limit', 100);
(int) \RainLoop\Api::Config()->Get('labs', 'imap_large_thread_limit', 50);
\MailSo\Config::$SystemLogger = \RainLoop\Api::Logger();

View file

@ -291,7 +291,7 @@ Enables caching in the system'),
'imap_message_list_fast_simple_search' => array(true),
'imap_message_list_count_limit_trigger' => array(0),
'imap_message_list_date_filter' => array(0),
'imap_large_thread_limit' => array(100),
'imap_large_thread_limit' => array(50),
'imap_folder_list_limit' => array(200),
'imap_show_login_alert' => array(true),
'smtp_show_server_errors' => array(false),