Speedup Contacts Suggestions handling

This commit is contained in:
the-djmaze 2022-12-21 09:58:10 +01:00
parent 731ac52564
commit 2e3e1fa5fe
3 changed files with 58 additions and 122 deletions

View file

@ -18,16 +18,12 @@ trait User
use Attachments; use Attachments;
use Pgp; use Pgp;
/** private ?Suggestions $oSuggestionsProvider = null;
* @var \RainLoop\Providers\Suggestions
*/
private $oSuggestionsProvider = null;
public function SuggestionsProvider(): Suggestions public function SuggestionsProvider(): Suggestions
{ {
if (null === $this->oSuggestionsProvider) { if (null === $this->oSuggestionsProvider) {
$this->oSuggestionsProvider = new Suggestions( $this->oSuggestionsProvider = new Suggestions($this->fabrica('suggestions'));
$this->fabrica('suggestions'));
} }
return $this->oSuggestionsProvider; return $this->oSuggestionsProvider;
@ -51,16 +47,13 @@ trait User
$this->Plugins()->RunHook('login.success', array($oAccount)); $this->Plugins()->RunHook('login.success', array($oAccount));
$sLanguage = $this->GetActionParam('Language', ''); $sLanguage = $this->GetActionParam('Language', '');
if ($oAccount && $sLanguage) if ($oAccount && $sLanguage) {
{
$oSettings = $this->SettingsProvider()->Load($oAccount); $oSettings = $this->SettingsProvider()->Load($oAccount);
if ($oSettings) if ($oSettings) {
{
$sLanguage = $this->ValidateLanguage($sLanguage); $sLanguage = $this->ValidateLanguage($sLanguage);
$sCurrentLanguage = $oSettings->GetConf('Language', ''); $sCurrentLanguage = $oSettings->GetConf('Language', '');
if ($sCurrentLanguage !== $sLanguage) if ($sCurrentLanguage !== $sLanguage) {
{
$oSettings->SetConf('Language', $sLanguage); $oSettings->SetConf('Language', $sLanguage);
$this->SettingsProvider()->Save($oAccount, $oSettings); $this->SettingsProvider()->Save($oAccount, $oSettings);
} }
@ -98,20 +91,17 @@ trait User
$iMainCacheTime = !empty($aTimers[0]) && \is_numeric($aTimers[0]) ? (int) $aTimers[0] : 0; $iMainCacheTime = !empty($aTimers[0]) && \is_numeric($aTimers[0]) ? (int) $aTimers[0] : 0;
$iFilesCacheTime = !empty($aTimers[1]) && \is_numeric($aTimers[1]) ? (int) $aTimers[1] : 0; $iFilesCacheTime = !empty($aTimers[1]) && \is_numeric($aTimers[1]) ? (int) $aTimers[1] : 0;
if (0 === $iMainCacheTime || $iMainCacheTime + $iOneDay1 < \time()) if (0 === $iMainCacheTime || $iMainCacheTime + $iOneDay1 < \time()) {
{
$bMainCache = true; $bMainCache = true;
$iMainCacheTime = \time(); $iMainCacheTime = \time();
} }
if (0 === $iFilesCacheTime || $iFilesCacheTime + $iOneDay2 < \time()) if (0 === $iFilesCacheTime || $iFilesCacheTime + $iOneDay2 < \time()) {
{
$bFilesCache = true; $bFilesCache = true;
$iFilesCacheTime = \time(); $iFilesCacheTime = \time();
} }
if ($bMainCache || $bFilesCache) if ($bMainCache || $bFilesCache) {
{
if (!$this->StorageProvider()->Put(null, if (!$this->StorageProvider()->Put(null,
\RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, 'Cache/Timers', \RainLoop\Providers\Storage\Enumerations\StorageType::NOBODY, 'Cache/Timers',
\implode(',', array($iMainCacheTime, $iFilesCacheTime)))) \implode(',', array($iMainCacheTime, $iFilesCacheTime))))
@ -120,8 +110,7 @@ trait User
} }
} }
if ($bMainCache) if ($bMainCache) {
{
$this->Logger()->Write('Cacher GC: Begin'); $this->Logger()->Write('Cacher GC: Begin');
$this->Cacher()->GC(48); $this->Cacher()->GC(48);
$this->Logger()->Write('Cacher GC: End'); $this->Logger()->Write('Cacher GC: End');
@ -129,9 +118,7 @@ trait User
$this->Logger()->Write('Storage GC: Begin'); $this->Logger()->Write('Storage GC: Begin');
$this->StorageProvider()->GC(); $this->StorageProvider()->GC();
$this->Logger()->Write('Storage GC: End'); $this->Logger()->Write('Storage GC: End');
} } else if ($bFilesCache) {
else if ($bFilesCache)
{
$this->Logger()->Write('Files GC: Begin'); $this->Logger()->Write('Files GC: Begin');
$this->FilesProvider()->GC(48); $this->FilesProvider()->GC(48);
$this->Logger()->Write('Files GC: End'); $this->Logger()->Write('Files GC: End');
@ -152,29 +139,23 @@ trait User
$oSettings = $this->SettingsProvider()->Load($oAccount); $oSettings = $this->SettingsProvider()->Load($oAccount);
$oSettingsLocal = $this->SettingsProvider(true)->Load($oAccount); $oSettingsLocal = $this->SettingsProvider(true)->Load($oAccount);
if ($oConfig->Get('webmail', 'allow_languages_on_settings', true)) if ($oConfig->Get('webmail', 'allow_languages_on_settings', true)) {
{
$this->setSettingsFromParams($oSettings, 'Language', 'string', function ($sLanguage) use ($self) { $this->setSettingsFromParams($oSettings, 'Language', 'string', function ($sLanguage) use ($self) {
return $self->ValidateLanguage($sLanguage); return $self->ValidateLanguage($sLanguage);
}); });
} } else {
else
{
// $oSettings->SetConf('Language', $this->ValidateLanguage($oConfig->Get('webmail', 'language', 'en'))); // $oSettings->SetConf('Language', $this->ValidateLanguage($oConfig->Get('webmail', 'language', 'en')));
} }
$this->setSettingsFromParams($oSettings, 'hourCycle', 'string'); $this->setSettingsFromParams($oSettings, 'hourCycle', 'string');
if ($this->GetCapa(Capa::THEMES)) if ($this->GetCapa(Capa::THEMES)) {
{
$this->setSettingsFromParams($oSettingsLocal, 'Theme', 'string', function ($sTheme) use ($self) { $this->setSettingsFromParams($oSettingsLocal, 'Theme', 'string', function ($sTheme) use ($self) {
return $self->ValidateTheme($sTheme); return $self->ValidateTheme($sTheme);
}); });
$this->setSettingsFromParams($oSettings, 'fontSansSerif', 'string'); $this->setSettingsFromParams($oSettings, 'fontSansSerif', 'string');
$this->setSettingsFromParams($oSettings, 'fontSerif', 'string'); $this->setSettingsFromParams($oSettings, 'fontSerif', 'string');
$this->setSettingsFromParams($oSettings, 'fontMono', 'string'); $this->setSettingsFromParams($oSettings, 'fontMono', 'string');
} } else {
else
{
// $oSettingsLocal->SetConf('Theme', $this->ValidateTheme($oConfig->Get('webmail', 'theme', 'Default'))); // $oSettingsLocal->SetConf('Theme', $this->ValidateTheme($oConfig->Get('webmail', 'theme', 'Default')));
} }
@ -229,8 +210,7 @@ trait User
{ {
$oAccount = $this->initMailClientConnection(); $oAccount = $this->initMailClientConnection();
if (!$this->GetCapa(Capa::QUOTA)) if (!$this->GetCapa(Capa::QUOTA)) {
{
return $this->DefaultResponse(__FUNCTION__, array(0, 0, 0, 0)); return $this->DefaultResponse(__FUNCTION__, array(0, 0, 0, 0));
} }
@ -253,34 +233,25 @@ trait User
$sQuery = \trim($this->GetActionParam('Query', '')); $sQuery = \trim($this->GetActionParam('Query', ''));
$iLimit = (int) $this->Config()->Get('contacts', 'suggestions_limit', 20); $iLimit = (int) $this->Config()->Get('contacts', 'suggestions_limit', 20);
$aResult = array();
$this->Plugins()->RunHook('json.suggestions-input-parameters', array(&$sQuery, &$iLimit, $oAccount)); $this->Plugins()->RunHook('json.suggestions-input-parameters', array(&$sQuery, &$iLimit, $oAccount));
$iLimit = (int) $iLimit; $iLimit = \max(5, (int) $iLimit);
if (5 > $iLimit)
{
$iLimit = 5;
}
$this->Plugins()->RunHook('json.suggestions-pre', array(&$aResult, $sQuery, $oAccount, $iLimit)); $aResult = array();
if ($iLimit > \count($aResult) && \strlen($sQuery)) if (\strlen($sQuery)) {
{
try try
{ {
// Address Book // Address Book
$oAddressBookProvider = $this->AddressBookProvider($oAccount); $oAddressBookProvider = $this->AddressBookProvider($oAccount);
if ($oAddressBookProvider && $oAddressBookProvider->IsActive()) if ($oAddressBookProvider && $oAddressBookProvider->IsActive()) {
{
$aSuggestions = $oAddressBookProvider->GetSuggestions($sQuery, $iLimit); $aSuggestions = $oAddressBookProvider->GetSuggestions($sQuery, $iLimit);
if (!\count($aResult)) foreach ($aSuggestions as $aItem) {
{ // Unique email address
$aResult = $aSuggestions; $sLine = \mb_strtolower($aItem[0]);
if (!isset($aResult[$sLine])) {
$aResult[$sLine] = $aItem;
} }
else
{
$aResult = \array_merge($aResult, $aSuggestions);
} }
} }
} }
@ -288,34 +259,20 @@ trait User
{ {
$this->Logger()->WriteException($oException); $this->Logger()->WriteException($oException);
} }
}
if ($iLimit > \count($aResult) && \strlen($sQuery)) if ($iLimit > \count($aResult)) {
{
$oSuggestionsProvider = $this->SuggestionsProvider(); $oSuggestionsProvider = $this->SuggestionsProvider();
if ($oSuggestionsProvider && $oSuggestionsProvider->IsActive()) if ($oSuggestionsProvider && $oSuggestionsProvider->IsActive()) {
{ $aSuggestions = $oSuggestionsProvider->Process($oAccount, $sQuery, $iLimit);
$aSuggestionsProviderResult = $oSuggestionsProvider->Process($oAccount, $sQuery, $iLimit); foreach ($aSuggestions as $sLine => $aItem) {
if (\is_array($aSuggestionsProviderResult) && \count($aSuggestionsProviderResult)) if (!isset($aResult[$sLine])) {
{ $aResult[$sLine] = $aItem;
$aResult = \array_merge($aResult, $aSuggestionsProviderResult); }
}
} }
} }
} $aResult = \array_slice(\array_values($aResult), 0, $iLimit);
$aResult = Utils::RemoveSuggestionDuplicates($aResult);
if ($iLimit < \count($aResult))
{
$aResult = \array_slice($aResult, 0, $iLimit);
}
$this->Plugins()->RunHook('json.suggestions-post', array(&$aResult, $sQuery, $oAccount, $iLimit));
$aResult = Utils::RemoveSuggestionDuplicates($aResult);
if ($iLimit < \count($aResult))
{
$aResult = \array_slice($aResult, 0, $iLimit);
} }
return $this->DefaultResponse(__FUNCTION__, $aResult); return $this->DefaultResponse(__FUNCTION__, $aResult);
@ -325,14 +282,12 @@ trait User
{ {
$oAccount = $this->getAccountFromToken(); $oAccount = $this->getAccountFromToken();
if (!$this->GetCapa(Capa::USER_BACKGROUND)) if (!$this->GetCapa(Capa::USER_BACKGROUND)) {
{
return $this->FalseResponse(__FUNCTION__); return $this->FalseResponse(__FUNCTION__);
} }
$oSettings = $this->SettingsProvider()->Load($oAccount); $oSettings = $this->SettingsProvider()->Load($oAccount);
if ($oAccount && $oSettings) if ($oAccount && $oSettings) {
{
$this->StorageProvider()->Clear($oAccount, $this->StorageProvider()->Clear($oAccount,
\RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG, \RainLoop\Providers\Storage\Enumerations\StorageType::CONFIG,
'background' 'background'
@ -348,8 +303,7 @@ trait User
private function setSettingsFromParams(\RainLoop\Settings $oSettings, string $sConfigName, string $sType = 'string', ?callable $cCallback = null) : void private function setSettingsFromParams(\RainLoop\Settings $oSettings, string $sConfigName, string $sType = 'string', ?callable $cCallback = null) : void
{ {
if ($this->HasActionParam($sConfigName)) if ($this->HasActionParam($sConfigName)) {
{
$sValue = $this->GetActionParam($sConfigName, ''); $sValue = $this->GetActionParam($sConfigName, '');
switch ($sType) switch ($sType)
{ {

View file

@ -7,15 +7,14 @@ class Suggestions extends \RainLoop\Providers\AbstractProvider
/** /**
* @var \RainLoop\Providers\Suggestions\ISuggestions[] * @var \RainLoop\Providers\Suggestions\ISuggestions[]
*/ */
private $aDrivers; private ?array $aDrivers;
/** /**
* @param \RainLoop\Providers\Suggestions\ISuggestions[]|null $aDriver = null * @param \RainLoop\Providers\Suggestions\ISuggestions[]|null $aDriver = null
*/ */
public function __construct(?array $aDriver = null) public function __construct(?array $aDriver = null)
{ {
if (\is_array($aDriver)) if (\is_array($aDriver)) {
{
$aDriver = \array_filter($aDriver, function ($oDriver) { $aDriver = \array_filter($aDriver, function ($oDriver) {
return $oDriver instanceof \RainLoop\Providers\Suggestions\ISuggestions; return $oDriver instanceof \RainLoop\Providers\Suggestions\ISuggestions;
}); });
@ -26,31 +25,30 @@ class Suggestions extends \RainLoop\Providers\AbstractProvider
public function Process(\RainLoop\Model\Account $oAccount, string $sQuery, int $iLimit = 20) : array public function Process(\RainLoop\Model\Account $oAccount, string $sQuery, int $iLimit = 20) : array
{ {
$aSuggestions = array(); $aResult = array();
if ($this->IsActive() && \is_array($this->aDrivers) && \strlen($sQuery)) if (\strlen($sQuery) && $this->IsActive()) {
{ foreach ($this->aDrivers as $oDriver) {
foreach ($this->aDrivers as $oDriver) if ($oDriver) try {
{
$aSubs = null;
if ($oDriver)
{
$aSubs = $oDriver->Process($oAccount, $sQuery, $iLimit); $aSubs = $oDriver->Process($oAccount, $sQuery, $iLimit);
if (\is_array($aSubs) && \count($aSubs)) if ($aSubs) {
{ foreach ($aSubs as $aItem) {
$aSuggestions = \array_merge($aSuggestions, $aSubs); // Unique email address
$sLine = \mb_strtolower($aItem[0]);
if (!isset($aResult[$sLine])) {
$aResult[$sLine] = $aItem;
} }
} }
if ($iLimit < \count($aResult)) {
break;
}
}
} catch (\Throwable $oException) {
$this->oLogger && $this->oLogger->WriteException($oException);
}
} }
} }
$aResult = \RainLoop\Utils::RemoveSuggestionDuplicates($aSuggestions); return \array_slice($aResult, 0, $iLimit);
if ($iLimit < \count($aResult))
{
$aResult = \array_slice($aResult, 0, $iLimit);
}
return $aResult;
} }
public function IsActive() : bool public function IsActive() : bool

View file

@ -251,22 +251,6 @@ class Utils
return self::WebVersionPath() . 'static/' . $path; return self::WebVersionPath() . 'static/' . $path;
} }
public static function RemoveSuggestionDuplicates(array $aSuggestions) : array
{
$aResult = array();
foreach ($aSuggestions as $aItem)
{
$sLine = \implode('~~', $aItem);
if (!isset($aResult[$sLine]))
{
$aResult[$sLine] = $aItem;
}
}
return array_values($aResult);
}
public static function inOpenBasedir(string $name) : string public static function inOpenBasedir(string $name) : string
{ {
static $open_basedir; static $open_basedir;