mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-08 22:18:28 +03:00
Use caching and a fetch queue to fetch avatars slowly without overloading server #115
This commit is contained in:
parent
5069bc2950
commit
0deedbecf5
3 changed files with 122 additions and 44 deletions
|
|
@ -1,8 +1,57 @@
|
|||
(rl => {
|
||||
// if (rl.settings.get('Nextcloud'))
|
||||
const
|
||||
templateId = 'MailMessageView';
|
||||
// DATA_IMAGE_USER_DOT_PIC = 'data:image/svg+xml;utf8,<svg version="1.1" xml:space="preserve" width="74.279999" height="86.666664" viewBox="0 0 74.279999 86.666664" xmlns="http://www.w3.org/2000/svg"><path d="M 557.17264,0 25.567509,-0.90909091 C 3.878663,-1.0561896 0.22727273,-0.69278176 0,92.8594 0,215.105 185.715,278.574 185.715,278.574 c 0,0 10.629,18.985 0,46.426 -39.047,28.785 -43.828,73.824 -46.43,185.715 C 147.316,622.742 225.969,650 278.57,650 331.18,650 409.82,622.793 417.859,510.715 415.262,398.824 410.477,353.785 371.434,325 c -10.637,-27.395 0,-46.426 0,-46.426 0,0 185.711,-63.469 185.711,-185.7146" style="fill:#AAAAAA;fill-opacity:1;fill-rule:nonzero;stroke:none" transform="matrix(0.13333333,0,0,-0.13333333,0,86.666667)"/></svg>';
|
||||
queue = [],
|
||||
avatars = new Map,
|
||||
templateId = 'MailMessageView',
|
||||
getAvatarUid = msg => {
|
||||
let from = msg.from[0],
|
||||
bimi = 'pass' == from.dkimStatus ? 1 : 0;
|
||||
return `${bimi}/${from.email}`;
|
||||
},
|
||||
getAvatar = msg => avatars.get(getAvatarUid(msg)),
|
||||
runQueue = (() => {
|
||||
let item = queue.shift();
|
||||
while (item) {
|
||||
let url = getAvatar(item[0]);
|
||||
if (url) {
|
||||
item[1](url);
|
||||
item = queue.shift();
|
||||
} else {
|
||||
// TODO: fetch vCard from Nextcloud contacts
|
||||
// let cfg = rl.settings.get('Nextcloud'),
|
||||
|
||||
let from = item[0].from[0];
|
||||
rl.pluginRemoteRequest((iError, data) => {
|
||||
if (!iError && data?.Result.type) {
|
||||
url = `data:${data.Result.type};base64,${data.Result.data}`;
|
||||
avatars.set(getAvatarUid(item[0]), url);
|
||||
item[1](url);
|
||||
}
|
||||
runQueue();
|
||||
}, 'Avatar', {
|
||||
bimi: 'pass' == from.dkimStatus ? 1 : 0,
|
||||
email: from.email
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}).debounce(1000);
|
||||
|
||||
ko.bindingHandlers.fromPic = {
|
||||
init: (element, self, dummy, msg) => {
|
||||
if (msg) {
|
||||
let url = getAvatar(msg),
|
||||
fn = url=>{element.src = url};
|
||||
if (url) {
|
||||
fn(url);
|
||||
} else {
|
||||
queue.push([msg, fn]);
|
||||
runQueue();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
addEventListener('rl-view-model.create', e => {
|
||||
if (templateId === e.detail.viewModelTemplateID) {
|
||||
|
|
@ -24,39 +73,28 @@
|
|||
view.message.subscribe(msg => {
|
||||
view.viewUserPicVisible(false);
|
||||
if (msg) {
|
||||
let from = msg.from[0],
|
||||
bimi = 'pass' == from.dkimStatus ? 1 : 0;
|
||||
// view.viewUserPic(`?Avatar/${bimi}/${encodeURIComponent(from.email)}`);
|
||||
// view.viewUserPicVisible(true);
|
||||
rl.pluginRemoteRequest((iError, data) => {
|
||||
if (!iError && data?.Result.type) {
|
||||
view.viewUserPic(`data:${data.Result.type};base64,${data.Result.data}`);
|
||||
let url = getAvatar(msg),
|
||||
fn = url => {
|
||||
view.viewUserPic(url);
|
||||
view.viewUserPicVisible(true);
|
||||
}
|
||||
}, 'Avatar', {
|
||||
bimi: bimi,
|
||||
email: from.email
|
||||
});
|
||||
};
|
||||
if (url) {
|
||||
fn(url);
|
||||
} else {
|
||||
// let from = msg.from[0], bimi = 'pass' == from.dkimStatus ? 1 : 0;
|
||||
// view.viewUserPic(`?Avatar/${bimi}/${encodeURIComponent(from.email)}`);
|
||||
// view.viewUserPicVisible(true);
|
||||
queue.push([msg, fn]);
|
||||
runQueue();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
/*
|
||||
|
||||
if ('MailMessageList' === e.detail.viewModelTemplateID) {
|
||||
const
|
||||
template = document.getElementById('MailMessageList' ),
|
||||
messageCheckbox = template.content.querySelector('.messageCheckbox');
|
||||
messageCheckbox.dataset.bind = 'attr:{style:$root.viewUserPic($data)}';
|
||||
e.detail.viewUserPic = msg => {
|
||||
let from = msg.from[0],
|
||||
bimi = 'pass' == from.dkimStatus ? 1 : 0;
|
||||
return `background:no-repeat url("?Avatar/${bimi}/${encodeURIComponent(from.email)}") center / contain`;
|
||||
return `background:no-repeat url("?Avatar/${bimi}/${encodeURIComponent(from.email)}") right / 32px;width:68px`;
|
||||
};
|
||||
.checkboxMessage {
|
||||
background: #000;
|
||||
}
|
||||
document.getElementById('MailMessageList').content.querySelector('.messageCheckbox')
|
||||
.append(Element.fromHTML(`<img class="fromPic" data-bind="fromPic:$data">`));
|
||||
}
|
||||
*/
|
||||
});
|
||||
|
||||
})(window.rl);
|
||||
|
|
|
|||
|
|
@ -58,20 +58,38 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
|||
|
||||
$aResult = null;
|
||||
|
||||
// TODO: lookup contacts vCard
|
||||
$oAccount = $oActions->getAccountFromToken();
|
||||
if ($oAccount) {
|
||||
$oAddressBookProvider = $oActions->AddressBookProvider($oAccount);
|
||||
if ($oAddressBookProvider) {
|
||||
$oContact = $oAddressBookProvider->GetContactByEmail($sEmail);
|
||||
if ($oContact && $oContact->vCard && $oContact->vCard['PHOTO']) {
|
||||
$aResult = [
|
||||
'text/vcard',
|
||||
$oContact->vCard
|
||||
];
|
||||
$sAsciiEmail = \MailSo\Base\Utils::IdnToAscii($sEmail, true);
|
||||
$sEmailId = \sha1(\strtolower($sAsciiEmail));
|
||||
|
||||
$sFile = \APP_PRIVATE_DATA . 'avatars/' . $sEmailId;
|
||||
$aFiles = \glob("{$sFile}.*");
|
||||
if ($aFiles) {
|
||||
$aResult = [
|
||||
\mime_content_type($aFiles[0]),
|
||||
\file_get_contents($aFiles[0])
|
||||
];
|
||||
$oActions->cacheByKey($sEmail);
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
// TODO: lookup contacts vCard and return PHOTO value
|
||||
/*
|
||||
if (!$aResult) {
|
||||
$oAccount = $oActions->getAccountFromToken();
|
||||
if ($oAccount) {
|
||||
$oAddressBookProvider = $oActions->AddressBookProvider($oAccount);
|
||||
if ($oAddressBookProvider) {
|
||||
$oContact = $oAddressBookProvider->GetContactByEmail($sEmail);
|
||||
if ($oContact && $oContact->vCard && $oContact->vCard['PHOTO']) {
|
||||
$aResult = [
|
||||
'text/vcard',
|
||||
$oContact->vCard
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
if (!$aResult) {
|
||||
$sDomain = \explode('@', $sEmail);
|
||||
|
|
@ -89,7 +107,6 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
|||
}
|
||||
|
||||
// TODO: make Gravatar optional
|
||||
$sAsciiEmail = \MailSo\Base\Utils::IdnToAscii($sEmail, true);
|
||||
$aUrls[] = 'http://gravatar.com/avatar/'.\md5(\strtolower($sAsciiEmail)).'?s=80&d=404';
|
||||
|
||||
foreach ($aUrls as $sUrl) {
|
||||
|
|
@ -99,6 +116,16 @@ class AvatarsPlugin extends \RainLoop\Plugins\AbstractPlugin
|
|||
}
|
||||
}
|
||||
|
||||
if ($aResult) {
|
||||
if (!\is_dir(\APP_PRIVATE_DATA . 'avatars')) {
|
||||
\mkdir(\APP_PRIVATE_DATA . 'avatars', 0700);
|
||||
}
|
||||
\file_put_contents(
|
||||
$sFile . \SnappyMail\File\MimeType::toExtension($aResult[0]),
|
||||
$aResult[1]
|
||||
);
|
||||
}
|
||||
|
||||
if (!$aResult) {
|
||||
$aServices = [
|
||||
"services/{$sDomain}",
|
||||
|
|
|
|||
|
|
@ -3,9 +3,22 @@
|
|||
float: left;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
padding: 2px;
|
||||
margin: 0 5px 0 0;
|
||||
background: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border: 1px solid var(--border-color, #ddd);
|
||||
border-radius: 6px;
|
||||
}
|
||||
/*
|
||||
.checkboxMessage {
|
||||
background: #000 no-repeat center / contain;
|
||||
background: #000 no-repeat right / 32px;
|
||||
width:68px
|
||||
}
|
||||
*/
|
||||
#rl-app .messageCheckbox {
|
||||
padding-right:0;
|
||||
white-space:nowrap;
|
||||
}
|
||||
.messageCheckbox .fromPic {
|
||||
margin: -0.6em 0 -0.6em 0.4em;
|
||||
height: 2em;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue