40 private const RENEW_LIMIT = 5;
41 private const FIX_LIMIT = 5;
42 private const RENEW_INTERVAL_CHANNEL = 14400;
43 private const PAUSE_INTERVAL_CHANNEL = 72000;
44 private const TYPE_LINK =
'SECTION_CONNECTION';
45 private const TYPE_CONNECTION =
'CONNECTION';
46 private const GOOGLE_CONNECTION =
'google_api_oauth';
47 private const OFFICE365_CONNECTION =
'office365';
48 private const RESULT_STATUS = [
53 private $mapperFactory;
57 private static array $outgoingManagersCache = [];
66 if (!Loader::includeModule(
'dav'))
71 $this->mapperFactory = ServiceLocator::getInstance()->get(
'calendar.service.mappers.factory');
87 if (!Loader::includeModule(
'dav') || !Loader::includeModule(
'calendar'))
92 $agentName = __METHOD__ .
'();';
93 $manager =
new static();
95 $status = $manager->doRenewWatchChannels();
97 $manager->doFixWatchSectionChannels();
98 $manager->doFixWatchConnectionChannels();
100 if ($status === self::RESULT_STATUS[
'done'])
103 time() + self::PAUSE_INTERVAL_CHANNEL)->format(Date::convertFormatToPhp(FORMAT_DATETIME)
106 CAgent::removeAgent($agentName,
"calendar");
107 CAgent::addAgent($agentName,
"calendar",
"N", self::RENEW_INTERVAL_CHANNEL,
"",
"Y", $nextAgentDate);
124 private function doRenewWatchChannels(): string
126 $pushChannels = PushTable::getList([
128 'ENTITY_TYPE' => [self::TYPE_LINK, self::TYPE_CONNECTION],
129 '<=EXPIRES' => (
new DateTime())->add(
'+1 day'),
134 'limit' => self::RENEW_LIMIT,
135 ])->fetchCollection();
137 foreach ($pushChannels as $pushChannelEO)
141 if ($pushChannel->getEntityType() === self::TYPE_LINK)
143 $this->renewSectionPush($pushChannel);
145 elseif ($pushChannel->getEntityType() === self::TYPE_CONNECTION)
147 $this->renewConnectionPush($pushChannel);
151 if ($pushChannels->count() < self::RENEW_LIMIT)
153 return self::RESULT_STATUS[
'done'];
156 return self::RESULT_STATUS[
'next'];
166 private function deleteChannel(Push $pushChannel): void
168 (
new PushManager())->deletePush($pushChannel);
178 private function savePushChannel(Push $pushChannel): void
180 (
new PushManager())->updatePush($pushChannel);
188 private function getFactoryByConnection(Connection $connection): ?FactoryInterface
190 $context =
new Context([
191 'connection' => $connection,
193 return FactoryBuilder::create($connection->getVendor()->getCode(), $connection, $context);
204 private function renewPushChannel(PushManagerInterface $vendorPushManager, Push $pushChannel): Result
208 $result = $vendorPushManager->renewPush($pushChannel);
210 if ($result->isSuccess())
212 $this->savePushChannel($pushChannel);
216 $result->addError(
new Error(
'Error of renew push channel.'));
219 catch(SyncException $e)
221 $result = (
new Result())->
addError(
new Error(
'Error of renew push channel.', $e->getCode()));
237 private function recreateSectionPushChannel(
238 PushManagerInterface $vendorPushManager,
240 SectionConnection $sectionLink
243 $result =
new Result();
246 $vendorPushManager->deletePush($pushChannel);
247 $result = $vendorPushManager->addSectionPush($sectionLink);
248 if ($result->isSuccess() && !empty($result->getData()))
250 $data = $result->getData();
252 ->setChannelId($data[
'CHANNEL_ID'])
253 ->setResourceId($data[
'RESOURCE_ID'])
254 ->setExpireDate(
new \
Bitrix\Calendar\Core\Base\Date($data[
'EXPIRES']));
255 $this->savePushChannel($pushChannel);
259 $result->addError(
new Error(
'Error of create push channel.'));
262 catch(ApiException $e)
264 $result->addError(
new Error(
'ApiException during creation of push channel.'));
265 if ($e->getMessage() ===
'ExtensionError')
267 $this->deleteChannel($pushChannel);
282 private function isError405(Result $result): bool
284 $errors = $result->getErrors();
289 foreach ($errors as $error)
291 if ((
int)$error->getCode() === 405)
303 private function getLinkFactory(): SectionConnectionFactory
305 if (empty($this->linkFactory))
307 $this->linkFactory =
new SectionConnectionFactory();
310 return $this->linkFactory;
324 private function renewSectionPush(Push $pushChannel): void
326 $sectionLink = $this->getLinkFactory()->getSectionConnection([
328 '=ID' => $pushChannel->getEntityId(),
332 $sectionLink !==
null
333 && $sectionLink->isActive()
334 && ($sectionLink->getConnection() !==
null)
335 && !$sectionLink->getConnection()->isDeleted()
339 $vendorFactory = $this->getFactoryByConnection($sectionLink->getConnection());
341 if ($vendorPushManager = $vendorFactory->getPushManager())
343 $now =
new DateTime();
344 if ($pushChannel->getExpireDate()->getDate() > $now)
346 $result = $this->renewPushChannel($vendorPushManager, $pushChannel);
347 if ($result->isSuccess())
351 elseif ($result->getErrorCollection()->getErrorByCode(405))
353 $result = $this->recreateSectionPushChannel($vendorPushManager, $pushChannel, $sectionLink);
354 if ($result->isSuccess())
359 elseif ($result->getErrorCollection()->getErrorByCode(401))
366 $result = $this->recreateSectionPushChannel($vendorPushManager, $pushChannel, $sectionLink);
367 if ($result->isSuccess())
375 $this->deleteChannel($pushChannel);
389 private function renewConnectionPush(Push $pushChannel): void
392 $connection = $this->getConnectionMapper()->getById($pushChannel->getEntityId());
393 if ($connection !==
null && !$connection->isDeleted())
396 $vendorFactory = $this->getFactoryByConnection($connection);
398 if ($vendorPushManager = $vendorFactory->getPushManager())
400 $result = $this->recreateConnectionPushChannel($vendorPushManager, $pushChannel, $connection);
401 if ($result->isSuccess())
408 $this->deleteChannel($pushChannel);
414 private function getConnectionMapper(): \
Bitrix\Calendar\Core\Mappers\Connection
416 return $this->mapperFactory->getConnection();
428 private function recreateConnectionPushChannel(
429 PushManagerInterface $vendorPushManager,
431 Connection $connection
434 $vendorPushManager->deletePush($pushChannel);
435 $result = $vendorPushManager->addConnectionPush($connection);
436 if ($result->isSuccess())
438 $data = $result->getData();
440 ->setResourceId($data[
'RESOURCE_ID'])
441 ->setExpireDate(
new \
Bitrix\Calendar\Core\Base\Date($data[
'EXPIRES']));
442 $this->savePushChannel($pushChannel);
446 $result->addError(
new Error(
'Error of create push channel.'));
459 private function doFixWatchSectionChannels(): void
461 $query = SectionConnectionTable::query()
462 ->setSelect([
'ID',
'CONNECTION_ID',
'SECTION_ID'])
463 ->registerRuntimeField(
'CONNECTION',
466 DavConnectionTable::getEntity(),
468 '=this.CONNECTION_ID' =>
'ref.ID',
470 [
'join_type' => Join::TYPE_INNER]
473 ->registerRuntimeField(
'PUSH',
476 PushTable::getEntity(),
478 '=this.ID' =>
'ref.ENTITY_ID',
479 'ref.ENTITY_TYPE' => [
'?', self::TYPE_LINK]
481 [
'join_type' => Join::TYPE_LEFT]
484 ->where(
'ACTIVE',
'Y')
485 ->where(
'LAST_SYNC_STATUS',
'success')
486 ->where(
'CONNECTION.IS_DELETED',
'N')
487 ->whereIn(
'CONNECTION.ACCOUNT_TYPE', [self::GOOGLE_CONNECTION, self::OFFICE365_CONNECTION])
488 ->whereNull(
'PUSH.ENTITY_TYPE')
489 ->setLimit(self::FIX_LIMIT)
493 while ($row = $query->Fetch())
495 $manager = $this->getOutgoingManager($row[
'CONNECTION_ID']);
497 $link = $this->mapperFactory->getSectionConnection()->getById($row[
'ID']);
500 $manager->subscribeSection($link);
505 $this->mapperFactory->getSectionConnection()->update($link);
516 private function doFixWatchConnectionChannels(): void
518 $query = DavConnectionTable::query()
520 ->registerRuntimeField(
'PUSH',
523 PushTable::getEntity(),
525 '=this.ID' =>
'ref.ENTITY_ID',
526 'ref.ENTITY_TYPE' => [
'?', self::TYPE_CONNECTION]
528 [
'join_type' => Join::TYPE_LEFT]
531 ->where(
'IS_DELETED',
'N')
532 ->where(
'ACCOUNT_TYPE', self::GOOGLE_CONNECTION)
533 ->whereIn(
'LAST_RESULT', [
'success',
'[200] OK'])
534 ->whereNull(
'PUSH.ENTITY_TYPE')
535 ->setLimit(self::FIX_LIMIT)
538 while ($row = $query->fetch())
542 $manager = $this->getOutgoingManager($row[
'ID']);
543 $manager->subscribeConnection();
547 DavConnectionTable::update($row[
'ID'], [
548 'LAST_RESULT' =>
'['. $e->getCode() .
'] ERR'
562 private function getOutgoingManager($connectionId): OutgoingManager
564 if (empty(static::$outgoingManagersCache[$connectionId]))
566 $connection = $this->mapperFactory->getConnection()->getById($connectionId);
567 static::$outgoingManagersCache[$connectionId] =
new OutgoingManager($connection);
570 return static::$outgoingManagersCache[$connectionId];