Cache getSharedWith() result

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
Co-authored-by: Carl Schwan <carl@carlschwan.eu>
This commit is contained in:
Maxence Lange 2022-04-02 11:21:18 -01:00
parent c4a4e859e6
commit 15d81a6ba5
10 changed files with 123 additions and 113 deletions

View file

@ -112,7 +112,7 @@ class ShareWrapperRequest extends ShareWrapperRequestBuilder {
/**
* @param Membership $membership
*/
public function removeByMembership(Membership $membership) {
public function deleteByMembership(Membership $membership) {
$qb = $this->getShareDeleteSql();
$qb->limitToShareWith($membership->getCircleId());
$qb->limit('uid_initiator', $membership->getSingleId());
@ -121,21 +121,6 @@ class ShareWrapperRequest extends ShareWrapperRequestBuilder {
}
/**
* @param string $initiator
* @param string $shareWith
*
* @deprecated in NC30 when initiator uses FederatedUser - then, we can use removeByMembership()
*/
public function removeByInitiatorAndShareWith(string $initiator, string $shareWith) {
$qb = $this->getShareDeleteSql();
$qb->limitToShareWith($shareWith);
$qb->limit('uid_initiator', $initiator);
$qb->execute();
}
/**
* @return array
*/
@ -441,13 +426,16 @@ class ShareWrapperRequest extends ShareWrapperRequestBuilder {
$qb->execute();
}
/**
* @param string $circleId
* @param string $initiator
*/
public function deleteFromCircle(string $circleId): void {
public function deleteSharesToCircle(string $circleId, string $initiator = ''): void {
$qb = $this->getShareDeleteSql();
$qb->andWhere($qb->exprLimit('share_with', $circleId));
if ($initiator !== '') {
$qb->limit('uid_initiator', $initiator);
}
$qb->execute();
}

View file

@ -121,58 +121,6 @@ class FileShare implements
}
$this->eventService->fileShareCreating($event, $mount);
// $this->eventService->federatedShareCreated($wrappedShare, $mount);
// $this->eventService->fileSharing($event);
// $this->mountRequest->create($mount);
// $circle = $event->getDeprecatedCircle();
//
// // if event is not local, we create a federated file to the right instance of Nextcloud, using the right token
// if (!$this->configService->isLocalInstance($event->getSource())) {
// try {
// $share = $this->getShareFromData($event->getData());
// } catch (Exception $e) {
// return;
// }
//
// $data = $event->getData();
// $token = $data->g('gs_federated');
// $filename = $data->g('gs_filename');
//
// $gsShare = new GSShare($share->getSharedWith(), $token);
// $gsShare->setOwner($share->getShareOwner());
// $gsShare->setInstance($event->getSource());
// $gsShare->setParent(-1);
// $gsShare->setMountPoint($filename);
//
// $this->gsSharesRequest->create($gsShare);
// } else {
// // if the event is local, we send mail to mail-as-members
// $members = $this->membersRequest->forceGetMembers(
// $circle->getUniqueId(), DeprecatedMember::LEVEL_MEMBER, DeprecatedMember::TYPE_MAIL, true
// );
//
// foreach ($members as $member) {
// $this->sendShareToContact($event, $circle, $member->getMemberId(), [$member->getUserId()]);
// }
// }
//
// // we also fill the event's result for further things, like contact-as-members
// $members = $this->membersRequest->forceGetMembers(
// $circle->getUniqueId(), DeprecatedMember::LEVEL_MEMBER, DeprecatedMember::TYPE_CONTACT, true
// );
//
// $accounts = [];
// foreach ($members as $member) {
// if ($member->getInstance() === '') {
// $accounts[] = $this->miscService->getInfosFromContact($member);
// }
// }
//
// $event->setResult(new SimpleDataStore(['contacts' => $accounts]));
}
@ -182,25 +130,5 @@ class FileShare implements
*/
public function result(FederatedEvent $event, array $results): void {
$this->eventService->fileShareCreated($event, $results);
// $event = null;
// $contacts = [];
// foreach (array_keys($events) as $instance) {
// $event = $events[$instance];
// $contacts = array_merge(
// $contacts, $event->getResult()
// ->gArray('contacts')
// );
// }
//
// if ($event === null || !$event->hasCircle()) {
// return;
// }
//
// $circle = $event->getDeprecatedCircle();
//
// foreach ($contacts as $contact) {
// $this->sendShareToContact($event, $circle, $contact['memberId'], $contact['emails']);
// }
}
}

View file

@ -77,6 +77,6 @@ class DestroyingCircle implements IEventListener {
}
$circle = $event->getCircle();
$this->shareWrapperService->deleteSharesToCircle($circle->getSingleId());
$this->shareWrapperService->deleteSharesToCircle($circle->getSingleId(), '', true);
}
}

View file

@ -31,7 +31,6 @@ declare(strict_types=1);
namespace OCA\Circles\Listeners\Files;
use OCA\Circles\Tools\Traits\TStringTools;
use OCA\Circles\CirclesManager;
use OCA\Circles\Db\ShareWrapperRequest;
use OCA\Circles\Events\MembershipsRemovedEvent;
@ -51,6 +50,8 @@ use OCA\Circles\Exceptions\UnknownRemoteException;
use OCA\Circles\Exceptions\UserTypeNotFoundException;
use OCA\Circles\Model\Member;
use OCA\Circles\Service\FederatedUserService;
use OCA\Circles\Service\ShareWrapperService;
use OCA\Circles\Tools\Traits\TStringTools;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
@ -66,8 +67,7 @@ class MembershipsRemoved implements IEventListener {
/** @var CirclesManager */
private $circlesManager;
/** @var ShareWrapperRequest */
private $shareWrapperRequest;
private ShareWrapperService $shareWrapperService;
/** @var FederatedUserService */
private $federatedUserService;
@ -77,16 +77,16 @@ class MembershipsRemoved implements IEventListener {
* MembershipsRemoved constructor.
*
* @param CirclesManager $circlesManager
* @param ShareWrapperRequest $shareWrapperRequest
* @param ShareWrapperService $shareWrapperService
* @param FederatedUserService $federatedUserService
*/
public function __construct(
CirclesManager $circlesManager,
ShareWrapperRequest $shareWrapperRequest,
ShareWrapperService $shareWrapperService,
FederatedUserService $federatedUserService
) {
$this->circlesManager = $circlesManager;
$this->shareWrapperRequest = $shareWrapperRequest;
$this->shareWrapperService = $shareWrapperService;
$this->federatedUserService = $federatedUserService;
}
@ -123,9 +123,9 @@ class MembershipsRemoved implements IEventListener {
$federatedUser = $this->circlesManager->getFederatedUser($membership->getSingleId());
if ($federatedUser->getUserType() === Member::TYPE_USER
&& $federatedUser->isLocal()) {
$this->shareWrapperRequest->removeByInitiatorAndShareWith(
$federatedUser->getUserId(),
$membership->getCircleId()
$this->shareWrapperService->deleteSharesToCircle(
$membership->getCircleId(),
$federatedUser->getUserId()
);
}
}

View file

@ -475,7 +475,7 @@ class FileCacheWrapper extends ManagedModel implements IQueryRow, IDeserializabl
->setPath($this->get('path', $data))
->setPermissions($this->getInt('permissions', $data))
->setStorage($this->get('storage', $data))
->setStorageId($this->getInt('storage', $data))
->setStorageId($this->getInt('storageId', $data))
->setPathHash($this->get('pathHash', $data))
->setParent($this->getInt('parent', $data))
->setName($this->get('name', $data))

View file

@ -366,6 +366,13 @@ class CircleProbe extends MemberProbe {
}
/**
* @return string
*/
public function getChecksum(): string {
return md5(json_encode($this->getAsOptions()));
}
/**
* Return a JSON object with includes as options
*

View file

@ -42,8 +42,8 @@ use OCA\Circles\Model\Circle;
use OCA\Circles\Model\Member;
use OCA\Circles\Model\Probes\CircleProbe;
use OCA\Circles\Model\ShareWrapper;
use OCP\IGroupManager;
use OCA\Circles\Tools\Traits\TNCLogger;
use OCP\IGroupManager;
use OCP\IUserManager;
use Symfony\Component\Console\Output\OutputInterface;
@ -80,6 +80,8 @@ class MaintenanceService {
/** @var FederatedUserService */
private $federatedUserService;
private ShareWrapperService $shareWrapperService;
/** @var MembershipService */
private $membershipService;
@ -101,11 +103,13 @@ class MaintenanceService {
* MaintenanceService constructor.
*
* @param IUserManager $userManager
* @param IGroupManager $groupManager
* @param CircleRequest $circleRequest
* @param MemberRequest $memberRequest
* @param ShareWrapperRequest $shareWrapperRequest
* @param SyncService $syncService
* @param FederatedUserService $federatedUserService
* @param ShareWrapperService $shareWrapperService
* @param MembershipService $membershipService
* @param EventWrapperService $eventWrapperService
* @param CircleService $circleService
@ -119,6 +123,7 @@ class MaintenanceService {
ShareWrapperRequest $shareWrapperRequest,
SyncService $syncService,
FederatedUserService $federatedUserService,
ShareWrapperService $shareWrapperService,
MembershipService $membershipService,
EventWrapperService $eventWrapperService,
CircleService $circleService,
@ -131,6 +136,7 @@ class MaintenanceService {
$this->shareWrapperRequest = $shareWrapperRequest;
$this->syncService = $syncService;
$this->federatedUserService = $federatedUserService;
$this->shareWrapperService = $shareWrapperService;
$this->eventWrapperService = $eventWrapperService;
$this->membershipService = $membershipService;
$this->circleService = $circleService;
@ -347,7 +353,7 @@ class MaintenanceService {
foreach ($shares as $share) {
if (!in_array($share, $circles)) {
$this->shareWrapperRequest->deleteFromCircle($share);
$this->shareWrapperService->deleteSharesToCircle($share, '', true);
}
}
}
@ -405,7 +411,7 @@ class MaintenanceService {
private function fixSubCirclesDisplayName(): void {
$probe = new CircleProbe();
$probe->includeSingleCircles();
$circles = $this->circleService->getCircles($probe);
foreach ($circles as $circle) {

View file

@ -31,8 +31,6 @@ declare(strict_types=1);
namespace OCA\Circles\Service;
use OCA\Circles\Tools\Exceptions\ItemNotFoundException;
use OCA\Circles\Tools\Traits\TNCLogger;
use OCA\Circles\Db\CircleRequest;
use OCA\Circles\Db\MemberRequest;
use OCA\Circles\Db\MembershipRequest;
@ -44,6 +42,8 @@ use OCA\Circles\Model\Circle;
use OCA\Circles\Model\FederatedUser;
use OCA\Circles\Model\Member;
use OCA\Circles\Model\Membership;
use OCA\Circles\Tools\Exceptions\ItemNotFoundException;
use OCA\Circles\Tools\Traits\TNCLogger;
/**
* Class MembershipService
@ -66,6 +66,8 @@ class MembershipService {
/** @var EventService */
private $eventService;
private ShareWrapperService $shareWrapperService;
/** @var OutputService */
private $outputService;
@ -77,6 +79,7 @@ class MembershipService {
* @param CircleRequest $circleRequest
* @param MemberRequest $memberRequest
* @param EventService $eventService
* @param ShareWrapperService $shareWrapperService
* @param OutputService $outputService
*/
public function __construct(
@ -84,12 +87,14 @@ class MembershipService {
CircleRequest $circleRequest,
MemberRequest $memberRequest,
EventService $eventService,
ShareWrapperService $shareWrapperService,
OutputService $outputService
) {
$this->membershipRequest = $membershipRequest;
$this->circleRequest = $circleRequest;
$this->memberRequest = $memberRequest;
$this->eventService = $eventService;
$this->shareWrapperService = $shareWrapperService;
$this->outputService = $outputService;
}
@ -337,6 +342,9 @@ class MembershipService {
if (!in_array($item->getCircleId(), $circleIds)) {
$deprecated[] = $item;
$this->membershipRequest->delete($item);
// clearing the getSharedWith() cache for singleId related to the membership
$this->shareWrapperService->clearCache($item->getSingleId());
}
}
@ -365,6 +373,9 @@ class MembershipService {
$this->membershipRequest->insert($membership);
$new[] = $membership;
}
// clearing the getSharedWith() cache for singleId related to the membership
$this->shareWrapperService->clearCache($membership->getSingleId());
}
return $new;

View file

@ -31,14 +31,19 @@ declare(strict_types=1);
namespace OCA\Circles\Service;
use OCA\Circles\Tools\Traits\TStringTools;
use Exception;
use OCA\Circles\Db\ShareWrapperRequest;
use OCA\Circles\Exceptions\RequestBuilderException;
use OCA\Circles\Exceptions\ShareWrapperNotFoundException;
use OCA\Circles\Model\FederatedUser;
use OCA\Circles\Model\Probes\CircleProbe;
use OCA\Circles\Model\ShareWrapper;
use OCA\Circles\Tools\Exceptions\InvalidItemException;
use OCA\Circles\Tools\Traits\TDeserialize;
use OCA\Circles\Tools\Traits\TStringTools;
use OCP\Files\NotFoundException;
use OCP\ICache;
use OCP\ICacheFactory;
use OCP\Share\IShare;
/**
@ -48,18 +53,27 @@ use OCP\Share\IShare;
*/
class ShareWrapperService {
use TStringTools;
use TDeserialize;
public const CACHE_SHARED_WITH = 'circles/getSharedWith';
public const CACHE_SHARED_WITH_TTL = 900;
/** @var ShareWrapperRequest */
private $shareWrapperRequest;
private ICache $cache;
/**
* ShareWrapperService constructor.
*
* @param ICacheFactory $cacheFactory
* @param ShareWrapperRequest $shareWrapperRequest
*/
public function __construct(ShareWrapperRequest $shareWrapperRequest) {
public function __construct(ICacheFactory $cacheFactory, ShareWrapperRequest $shareWrapperRequest) {
$this->cache = $cacheFactory->createDistributed(self::CACHE_SHARED_WITH);
$this->shareWrapperRequest = $shareWrapperRequest;
}
@ -83,6 +97,7 @@ class ShareWrapperService {
* @throws NotFoundException
*/
public function save(IShare $share): void {
$this->cache->clear('');
$this->shareWrapperRequest->save($share);
}
@ -91,6 +106,7 @@ class ShareWrapperService {
* @param ShareWrapper $shareWrapper
*/
public function update(ShareWrapper $shareWrapper): void {
$this->cache->clear('');
$this->shareWrapperRequest->update($shareWrapper);
}
@ -99,14 +115,24 @@ class ShareWrapperService {
* @param ShareWrapper $shareWrapper
*/
public function delete(ShareWrapper $shareWrapper): void {
$this->cache->clear('');
$this->shareWrapperRequest->delete((int)$shareWrapper->getId());
}
/**
* @param string $circleId
* @param string $initiator
* @param bool $force
*
* @throws Exception
*/
public function deleteSharesToCircle(string $circleId) {
$this->shareWrapperRequest->deleteFromCircle($circleId);
public function deleteSharesToCircle(string $circleId, string $initiator = '', bool $force = false): void {
if ($initiator === '' && !$force) {
throw new Exception('if initiator is empty, you need to set $force as true');
}
$this->cache->clear('');
$this->shareWrapperRequest->deleteSharesToCircle($circleId, $initiator);
}
@ -184,7 +210,22 @@ class ShareWrapperService {
int $nodeId,
?CircleProbe $probe
): array {
return $this->shareWrapperRequest->getSharedWith($federatedUser, $nodeId, $probe);
$key = $this->generateSharedWithCacheKey($federatedUser, $nodeId, $probe->getChecksum());
$cachedData = $this->cache->get($key);
try {
if (!is_string($cachedData)) {
throw new InvalidItemException();
}
return $this->deserializeArray($cachedData, ShareWrapper::class);
} catch (InvalidItemException $e) {
}
$shares = $this->shareWrapperRequest->getSharedWith($federatedUser, $nodeId, $probe);
$this->cache->set($key, json_encode($shares), self::CACHE_SHARED_WITH_TTL);
return $shares;
}
@ -247,6 +288,11 @@ class ShareWrapperService {
}
public function clearCache(string $singleId): void {
$this->cache->clear($singleId);
}
/**
* @param FederatedUser $federatedUser
* @param IShare $share
@ -257,9 +303,28 @@ class ShareWrapperService {
* @throws RequestBuilderException
*/
private function createChild(IShare $share, FederatedUser $federatedUser): ShareWrapper {
$this->cache->clear('');
$share->setSharedWith($federatedUser->getSingleId());
$childId = $this->shareWrapperRequest->save($share, (int)$share->getId());
return $this->getShareById($childId, $federatedUser);
}
/**
* @param FederatedUser $federatedUser
* @param int $nodeId
* @param string $probeSum
*
* @return string
*/
private function generateSharedWithCacheKey(
FederatedUser $federatedUser,
int $nodeId,
string $probeSum
): string {
return $federatedUser->getSingleId() . '#'
. $nodeId . '#'
. $probeSum;
}
}

View file

@ -78,14 +78,19 @@ trait TDeserialize {
/**
* @param array $data
* @param string $json
* @param string $class
*
* @return IDeserializable[]
* @throws InvalidItemException
*/
public function deserializeArray(array $data, string $class): array {
public function deserializeArray(string $json, string $class): array {
$arr = [];
$data = json_decode($json, true);
if (!is_array($data)) {
return $arr;
}
foreach ($data as $entry) {
$arr[] = $this->deserialize($entry, $class);
}