mirror of
https://github.com/nextcloud/server.git
synced 2026-05-28 04:32:30 -04:00
Merge pull request #56795 from nextcloud/feat/noid/extend-entity-to-be-snoflake-aware
feat(snowflake): extend Entity class to support snowflakes
This commit is contained in:
commit
40b79f5af8
37 changed files with 284 additions and 167 deletions
|
|
@ -44,7 +44,6 @@ use OCP\Share\Exceptions\ShareNotFound;
|
|||
use OCP\Share\IManager;
|
||||
use OCP\Share\IProviderFactory;
|
||||
use OCP\Share\IShare;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use OCP\Util;
|
||||
use Override;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
|
@ -70,7 +69,6 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
|
|||
private readonly IFilenameValidator $filenameValidator,
|
||||
private readonly IProviderFactory $shareProviderFactory,
|
||||
private readonly SetupManager $setupManager,
|
||||
private readonly IGenerator $snowflakeGenerator,
|
||||
private readonly ExternalShareMapper $externalShareMapper,
|
||||
) {
|
||||
}
|
||||
|
|
@ -145,7 +143,7 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
|
|||
}
|
||||
|
||||
$externalShare = new ExternalShare();
|
||||
$externalShare->setId($this->snowflakeGenerator->nextId());
|
||||
$externalShare->generateId();
|
||||
$externalShare->setRemote($remote);
|
||||
$externalShare->setRemoteId($remoteId);
|
||||
$externalShare->setShareToken($token);
|
||||
|
|
@ -177,9 +175,9 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
|
|||
->setType('remote_share')
|
||||
->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/'), $ownerDisplayName])
|
||||
->setAffectedUser($shareWith)
|
||||
->setObject('remote_share', $externalShare->getId(), $name);
|
||||
->setObject('remote_share', (string)$externalShare->getId(), $name);
|
||||
Server::get(IActivityManager::class)->publish($event);
|
||||
$this->notifyAboutNewShare($shareWith, $externalShare->getId(), $ownerFederatedId, $sharedByFederatedId, $name, $ownerDisplayName);
|
||||
$this->notifyAboutNewShare($shareWith, (string)$externalShare->getId(), $ownerFederatedId, $sharedByFederatedId, $name, $ownerDisplayName);
|
||||
|
||||
// If auto-accept is enabled, accept the share
|
||||
if ($this->federatedShareProvider->isFederatedTrustedShareAutoAccept() && $trustedServers?->isTrustedServer($remote) === true) {
|
||||
|
|
@ -193,9 +191,9 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
|
|||
->setType('remote_share')
|
||||
->setSubject(RemoteShares::SUBJECT_REMOTE_SHARE_RECEIVED, [$ownerFederatedId, trim($name, '/'), $ownerDisplayName])
|
||||
->setAffectedUser($user->getUID())
|
||||
->setObject('remote_share', $externalShare->getId(), $name);
|
||||
->setObject('remote_share', (string)$externalShare->getId(), $name);
|
||||
Server::get(IActivityManager::class)->publish($event);
|
||||
$this->notifyAboutNewShare($user->getUID(), $externalShare->getId(), $ownerFederatedId, $sharedByFederatedId, $name, $ownerDisplayName);
|
||||
$this->notifyAboutNewShare($user->getUID(), (string)$externalShare->getId(), $ownerFederatedId, $sharedByFederatedId, $name, $ownerDisplayName);
|
||||
|
||||
// If auto-accept is enabled, accept the share
|
||||
if ($this->federatedShareProvider->isFederatedTrustedShareAutoAccept() && $trustedServers?->isTrustedServer($remote) === true) {
|
||||
|
|
@ -204,7 +202,7 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
|
|||
}
|
||||
}
|
||||
|
||||
return $externalShare->getId();
|
||||
return (string)$externalShare->getId();
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->error('Server can not add remote share.', [
|
||||
'app' => 'files_sharing',
|
||||
|
|
@ -466,7 +464,7 @@ class CloudFederationProviderFiles implements ISignedCloudFederationProvider {
|
|||
$notification = $this->notificationManager->createNotification();
|
||||
$notification->setApp('files_sharing')
|
||||
->setUser($share->getUser())
|
||||
->setObject('remote_share', $share->getId());
|
||||
->setObject('remote_share', (string)$share->getId());
|
||||
$this->notificationManager->markProcessed($notification);
|
||||
|
||||
$event = $this->activityManager->generateEvent();
|
||||
|
|
|
|||
|
|
@ -12,15 +12,13 @@ namespace OCA\Files_Sharing\External;
|
|||
|
||||
use OC\Files\Filesystem;
|
||||
use OCA\Files_Sharing\ResponseDefinitions;
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\AppFramework\Db\SnowflakeAwareEntity;
|
||||
use OCP\DB\Types;
|
||||
use OCP\IGroup;
|
||||
use OCP\IUser;
|
||||
use OCP\Share\IShare;
|
||||
|
||||
/**
|
||||
* @method string getId()
|
||||
* @method void setId(string $id)
|
||||
* @method string getParent()
|
||||
* @method void setParent(string $parent)
|
||||
* @method int|null getShareType()
|
||||
|
|
@ -46,7 +44,7 @@ use OCP\Share\IShare;
|
|||
*
|
||||
* @psalm-import-type Files_SharingRemoteShare from ResponseDefinitions
|
||||
*/
|
||||
class ExternalShare extends Entity implements \JsonSerializable {
|
||||
class ExternalShare extends SnowflakeAwareEntity implements \JsonSerializable {
|
||||
protected string $parent = '-1';
|
||||
protected ?int $shareType = null;
|
||||
protected ?string $remote = null;
|
||||
|
|
@ -96,7 +94,7 @@ class ExternalShare extends Entity implements \JsonSerializable {
|
|||
public function jsonSerialize(): array {
|
||||
$parent = $this->getParent();
|
||||
return [
|
||||
'id' => $this->getId(),
|
||||
'id' => (string)$this->getId(),
|
||||
'parent' => $parent,
|
||||
'share_type' => $this->getShareType() ?? IShare::TYPE_USER, // unfortunately nullable on the DB level, but never null.
|
||||
'remote' => $this->getRemote(),
|
||||
|
|
|
|||
8
apps/files_sharing/lib/External/Manager.php
vendored
8
apps/files_sharing/lib/External/Manager.php
vendored
|
|
@ -34,7 +34,6 @@ use OCP\IUserSession;
|
|||
use OCP\Notification\IManager;
|
||||
use OCP\OCS\IDiscoveryService;
|
||||
use OCP\Share\IShare;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Manager {
|
||||
|
|
@ -57,7 +56,6 @@ class Manager {
|
|||
private SetupManager $setupManager,
|
||||
private ICertificateManager $certificateManager,
|
||||
private ExternalShareMapper $externalShareMapper,
|
||||
private IGenerator $snowflakeGenerator,
|
||||
) {
|
||||
$this->user = $userSession->getUser();
|
||||
}
|
||||
|
|
@ -186,7 +184,7 @@ class Manager {
|
|||
$subShare = $this->externalShareMapper->getUserShare($externalShare, $user);
|
||||
} catch (DoesNotExistException) {
|
||||
$subShare = new ExternalShare();
|
||||
$subShare->setId($this->snowflakeGenerator->nextId());
|
||||
$subShare->generateId();
|
||||
$subShare->setRemote($externalShare->getRemote());
|
||||
$subShare->setPassword($externalShare->getPassword());
|
||||
$subShare->setName($externalShare->getName());
|
||||
|
|
@ -195,7 +193,7 @@ class Manager {
|
|||
$subShare->setMountpoint($mountPoint ?? $externalShare->getMountpoint());
|
||||
$subShare->setAccepted($accepted);
|
||||
$subShare->setRemoteId($externalShare->getRemoteId());
|
||||
$subShare->setParent($externalShare->getId());
|
||||
$subShare->setParent((string)$externalShare->getId());
|
||||
$subShare->setShareType($externalShare->getShareType());
|
||||
$subShare->setShareToken($externalShare->getShareToken());
|
||||
$this->externalShareMapper->insert($subShare);
|
||||
|
|
@ -317,7 +315,7 @@ class Manager {
|
|||
$filter = $this->notificationManager->createNotification();
|
||||
$filter->setApp('files_sharing')
|
||||
->setUser($user->getUID())
|
||||
->setObject('remote_share', $remoteShare->getId());
|
||||
->setObject('remote_share', (string)$remoteShare->getId());
|
||||
$this->notificationManager->markProcessed($filter);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ use OCP\Federation\ICloudId;
|
|||
use OCP\Federation\ICloudIdManager;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Server;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use PHPUnit\Framework\Attributes\Group;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
|
@ -64,7 +63,7 @@ class CleanupRemoteStoragesTest extends TestCase {
|
|||
|
||||
if (isset($storage['share_token'])) {
|
||||
$externalShare = new ExternalShare();
|
||||
$externalShare->setId(Server::get(IGenerator::class)->nextId());
|
||||
$externalShare->generateId();
|
||||
$externalShare->setShareToken($storage['share_token']);
|
||||
$externalShare->setRemote($storage['remote']);
|
||||
$externalShare->setName('irrelevant');
|
||||
|
|
|
|||
|
|
@ -40,7 +40,6 @@ use OCP\IUserSession;
|
|||
use OCP\OCS\IDiscoveryService;
|
||||
use OCP\Server;
|
||||
use OCP\Share\IShare;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Test\Traits\UserTrait;
|
||||
|
|
@ -170,7 +169,6 @@ class ManagerTest extends TestCase {
|
|||
$this->setupManager,
|
||||
$this->certificateManager,
|
||||
$this->externalShareMapper,
|
||||
Server::get(IGenerator::class),
|
||||
]
|
||||
)->onlyMethods(['tryOCMEndPoint'])->getMock();
|
||||
}
|
||||
|
|
@ -190,7 +188,7 @@ class ManagerTest extends TestCase {
|
|||
|
||||
public function testAddUserShare(): void {
|
||||
$userShare = new ExternalShare();
|
||||
$userShare->setId(Server::get(IGenerator::class)->nextId());
|
||||
$userShare->generateId();
|
||||
$userShare->setRemote('http://localhost');
|
||||
$userShare->setShareToken('token1');
|
||||
$userShare->setPassword('');
|
||||
|
|
@ -205,7 +203,7 @@ class ManagerTest extends TestCase {
|
|||
|
||||
public function testAddGroupShare(): void {
|
||||
$groupShare = new ExternalShare();
|
||||
$groupShare->setId(Server::get(IGenerator::class)->nextId());
|
||||
$groupShare->generateId();
|
||||
$groupShare->setRemote('http://localhost');
|
||||
$groupShare->setOwner('foobar');
|
||||
$groupShare->setShareType(IShare::TYPE_GROUP);
|
||||
|
|
@ -237,10 +235,10 @@ class ManagerTest extends TestCase {
|
|||
|
||||
$shareData2 = $shareData1->clone();
|
||||
$shareData2->setShareToken('token2');
|
||||
$shareData2->setId(\OCP\Server::get(IGenerator::class)->nextId());
|
||||
$shareData2->generateId();
|
||||
$shareData3 = $shareData1->clone();
|
||||
$shareData3->setShareToken('token3');
|
||||
$shareData3->setId(\OCP\Server::get(IGenerator::class)->nextId());
|
||||
$shareData3->generateId();
|
||||
|
||||
$this->setupMounts();
|
||||
$this->assertNotMount('SharedFolder');
|
||||
|
|
@ -440,7 +438,7 @@ class ManagerTest extends TestCase {
|
|||
$user = $this->createMock(IUser::class);
|
||||
$user->expects($this->any())->method('getUID')->willReturn($userId);
|
||||
$share = new ExternalShare();
|
||||
$share->setId(Server::get(IGenerator::class)->nextId());
|
||||
$share->generateId();
|
||||
$share->setRemote('http://localhost');
|
||||
$share->setShareToken('token1');
|
||||
$share->setPassword('');
|
||||
|
|
@ -460,7 +458,7 @@ class ManagerTest extends TestCase {
|
|||
*/
|
||||
private function createTestGroupShare(string $groupId = 'group1'): array {
|
||||
$share = new ExternalShare();
|
||||
$share->setId(Server::get(IGenerator::class)->nextId());
|
||||
$share->generateId();
|
||||
$share->setRemote('http://localhost');
|
||||
$share->setShareToken('token1');
|
||||
$share->setPassword('');
|
||||
|
|
@ -646,7 +644,7 @@ class ManagerTest extends TestCase {
|
|||
// user 2 shares
|
||||
$manager2 = $this->createManagerForUser($user2);
|
||||
$share = new ExternalShare();
|
||||
$share->setId(Server::get(IGenerator::class)->nextId());
|
||||
$share->generateId();
|
||||
$share->setRemote('http://localhost');
|
||||
$share->setShareToken('token1');
|
||||
$share->setPassword('');
|
||||
|
|
@ -696,7 +694,7 @@ class ManagerTest extends TestCase {
|
|||
$manager2 = $this->createManagerForUser($user);
|
||||
|
||||
$share = new ExternalShare();
|
||||
$share->setId(Server::get(IGenerator::class)->nextId());
|
||||
$share->generateId();
|
||||
$share->setRemote('http://localhost');
|
||||
$share->setShareToken('token1');
|
||||
$share->setPassword('');
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ class VersionEntity extends Entity implements JsonSerializable {
|
|||
|
||||
public function jsonSerialize(): array {
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'id' => $this->getId(),
|
||||
'file_id' => $this->fileId,
|
||||
'timestamp' => $this->timestamp,
|
||||
'size' => $this->size,
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ use OCP\Files\IRootFolder;
|
|||
use OCP\IAppConfig;
|
||||
use OCP\IConfig;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use Override;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
|
|
@ -45,7 +44,6 @@ class MovePreviewJob extends TimedJob {
|
|||
private readonly IMimeTypeDetector $mimeTypeDetector,
|
||||
private readonly IMimeTypeLoader $mimeTypeLoader,
|
||||
private readonly LoggerInterface $logger,
|
||||
private readonly IGenerator $generator,
|
||||
IAppDataFactory $appDataFactory,
|
||||
) {
|
||||
parent::__construct($time);
|
||||
|
|
@ -138,7 +136,7 @@ class MovePreviewJob extends TimedJob {
|
|||
$path = $fileId . '/' . $previewFile->getName();
|
||||
/** @var SimpleFile $previewFile */
|
||||
$preview = Preview::fromPath($path, $this->mimeTypeDetector);
|
||||
$preview->setId($this->generator->nextId());
|
||||
$preview->generateId();
|
||||
if (!$preview) {
|
||||
$this->logger->error('Unable to import old preview at path.');
|
||||
continue;
|
||||
|
|
@ -172,6 +170,7 @@ class MovePreviewJob extends TimedJob {
|
|||
$preview->setStorageId($result[0]['storage']);
|
||||
$preview->setEtag($result[0]['etag']);
|
||||
$preview->setSourceMimeType($this->mimeTypeLoader->getMimetypeById((int)$result[0]['mimetype']));
|
||||
$preview->generateId();
|
||||
try {
|
||||
$preview = $this->previewMapper->insert($preview);
|
||||
} catch (Exception) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ declare(strict_types=1);
|
|||
*/
|
||||
namespace OC\Core\Command;
|
||||
|
||||
use OCP\Snowflake\IDecoder;
|
||||
use OCP\Snowflake\ISnowflakeDecoder;
|
||||
use Symfony\Component\Console\Helper\Table;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
|
|
@ -16,7 +16,7 @@ use Symfony\Component\Console\Output\OutputInterface;
|
|||
|
||||
class SnowflakeDecodeId extends Base {
|
||||
public function __construct(
|
||||
private readonly IDecoder $decoder,
|
||||
private readonly ISnowflakeDecoder $decoder,
|
||||
) {
|
||||
parent::__construct();
|
||||
}
|
||||
|
|
@ -36,13 +36,13 @@ class SnowflakeDecodeId extends Base {
|
|||
|
||||
$rows = [
|
||||
['Snowflake ID', $snowflakeId],
|
||||
['Seconds', $data['seconds']],
|
||||
['Milliseconds', $data['milliseconds']],
|
||||
['Created from CLI', $data['isCli'] ? 'yes' : 'no'],
|
||||
['Server ID', $data['serverId']],
|
||||
['Sequence ID', $data['sequenceId']],
|
||||
['Creation timestamp', $data['createdAt']->format('U.v')],
|
||||
['Creation date', $data['createdAt']->format('Y-m-d H:i:s.v')],
|
||||
['Seconds', $data->getSeconds()],
|
||||
['Milliseconds', $data->getMilliseconds()],
|
||||
['Created from CLI', $data->isCli() ? 'yes' : 'no'],
|
||||
['Server ID', $data->getServerId()],
|
||||
['Sequence ID', $data->getSequenceId()],
|
||||
['Creation timestamp', $data->getCreatedAt()->format('U.v')],
|
||||
['Creation date', $data->getCreatedAt()->format('Y-m-d H:i:s.v')],
|
||||
];
|
||||
|
||||
$table = new Table($output);
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ return array(
|
|||
'OCP\\AppFramework\\Db\\IMapperException' => $baseDir . '/lib/public/AppFramework/Db/IMapperException.php',
|
||||
'OCP\\AppFramework\\Db\\MultipleObjectsReturnedException' => $baseDir . '/lib/public/AppFramework/Db/MultipleObjectsReturnedException.php',
|
||||
'OCP\\AppFramework\\Db\\QBMapper' => $baseDir . '/lib/public/AppFramework/Db/QBMapper.php',
|
||||
'OCP\\AppFramework\\Db\\SnowflakeAwareEntity' => $baseDir . '/lib/public/AppFramework/Db/SnowflakeAwareEntity.php',
|
||||
'OCP\\AppFramework\\Db\\TTransactional' => $baseDir . '/lib/public/AppFramework/Db/TTransactional.php',
|
||||
'OCP\\AppFramework\\Http' => $baseDir . '/lib/public/AppFramework/Http.php',
|
||||
'OCP\\AppFramework\\Http\\Attribute\\ARateLimit' => $baseDir . '/lib/public/AppFramework/Http/Attribute/ARateLimit.php',
|
||||
|
|
@ -837,8 +838,9 @@ return array(
|
|||
'OCP\\Share_Backend' => $baseDir . '/lib/public/Share_Backend.php',
|
||||
'OCP\\Share_Backend_Collection' => $baseDir . '/lib/public/Share_Backend_Collection.php',
|
||||
'OCP\\Share_Backend_File_Dependent' => $baseDir . '/lib/public/Share_Backend_File_Dependent.php',
|
||||
'OCP\\Snowflake\\IDecoder' => $baseDir . '/lib/public/Snowflake/IDecoder.php',
|
||||
'OCP\\Snowflake\\IGenerator' => $baseDir . '/lib/public/Snowflake/IGenerator.php',
|
||||
'OCP\\Snowflake\\ISnowflakeDecoder' => $baseDir . '/lib/public/Snowflake/ISnowflakeDecoder.php',
|
||||
'OCP\\Snowflake\\ISnowflakeGenerator' => $baseDir . '/lib/public/Snowflake/ISnowflakeGenerator.php',
|
||||
'OCP\\Snowflake\\Snowflake' => $baseDir . '/lib/public/Snowflake/Snowflake.php',
|
||||
'OCP\\SpeechToText\\Events\\AbstractTranscriptionEvent' => $baseDir . '/lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php',
|
||||
'OCP\\SpeechToText\\Events\\TranscriptionFailedEvent' => $baseDir . '/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php',
|
||||
'OCP\\SpeechToText\\Events\\TranscriptionSuccessfulEvent' => $baseDir . '/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php',
|
||||
|
|
@ -2144,10 +2146,10 @@ return array(
|
|||
'OC\\Share\\Helper' => $baseDir . '/lib/private/Share/Helper.php',
|
||||
'OC\\Share\\Share' => $baseDir . '/lib/private/Share/Share.php',
|
||||
'OC\\Snowflake\\APCuSequence' => $baseDir . '/lib/private/Snowflake/APCuSequence.php',
|
||||
'OC\\Snowflake\\Decoder' => $baseDir . '/lib/private/Snowflake/Decoder.php',
|
||||
'OC\\Snowflake\\FileSequence' => $baseDir . '/lib/private/Snowflake/FileSequence.php',
|
||||
'OC\\Snowflake\\Generator' => $baseDir . '/lib/private/Snowflake/Generator.php',
|
||||
'OC\\Snowflake\\ISequence' => $baseDir . '/lib/private/Snowflake/ISequence.php',
|
||||
'OC\\Snowflake\\SnowflakeDecoder' => $baseDir . '/lib/private/Snowflake/SnowflakeDecoder.php',
|
||||
'OC\\Snowflake\\SnowflakeGenerator' => $baseDir . '/lib/private/Snowflake/SnowflakeGenerator.php',
|
||||
'OC\\SpeechToText\\SpeechToTextManager' => $baseDir . '/lib/private/SpeechToText/SpeechToTextManager.php',
|
||||
'OC\\SpeechToText\\TranscriptionJob' => $baseDir . '/lib/private/SpeechToText/TranscriptionJob.php',
|
||||
'OC\\StreamImage' => $baseDir . '/lib/private/StreamImage.php',
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
|
|||
'OCP\\AppFramework\\Db\\IMapperException' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Db/IMapperException.php',
|
||||
'OCP\\AppFramework\\Db\\MultipleObjectsReturnedException' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Db/MultipleObjectsReturnedException.php',
|
||||
'OCP\\AppFramework\\Db\\QBMapper' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Db/QBMapper.php',
|
||||
'OCP\\AppFramework\\Db\\SnowflakeAwareEntity' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Db/SnowflakeAwareEntity.php',
|
||||
'OCP\\AppFramework\\Db\\TTransactional' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Db/TTransactional.php',
|
||||
'OCP\\AppFramework\\Http' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http.php',
|
||||
'OCP\\AppFramework\\Http\\Attribute\\ARateLimit' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/ARateLimit.php',
|
||||
|
|
@ -878,8 +879,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
|
|||
'OCP\\Share_Backend' => __DIR__ . '/../../..' . '/lib/public/Share_Backend.php',
|
||||
'OCP\\Share_Backend_Collection' => __DIR__ . '/../../..' . '/lib/public/Share_Backend_Collection.php',
|
||||
'OCP\\Share_Backend_File_Dependent' => __DIR__ . '/../../..' . '/lib/public/Share_Backend_File_Dependent.php',
|
||||
'OCP\\Snowflake\\IDecoder' => __DIR__ . '/../../..' . '/lib/public/Snowflake/IDecoder.php',
|
||||
'OCP\\Snowflake\\IGenerator' => __DIR__ . '/../../..' . '/lib/public/Snowflake/IGenerator.php',
|
||||
'OCP\\Snowflake\\ISnowflakeDecoder' => __DIR__ . '/../../..' . '/lib/public/Snowflake/ISnowflakeDecoder.php',
|
||||
'OCP\\Snowflake\\ISnowflakeGenerator' => __DIR__ . '/../../..' . '/lib/public/Snowflake/ISnowflakeGenerator.php',
|
||||
'OCP\\Snowflake\\Snowflake' => __DIR__ . '/../../..' . '/lib/public/Snowflake/Snowflake.php',
|
||||
'OCP\\SpeechToText\\Events\\AbstractTranscriptionEvent' => __DIR__ . '/../../..' . '/lib/public/SpeechToText/Events/AbstractTranscriptionEvent.php',
|
||||
'OCP\\SpeechToText\\Events\\TranscriptionFailedEvent' => __DIR__ . '/../../..' . '/lib/public/SpeechToText/Events/TranscriptionFailedEvent.php',
|
||||
'OCP\\SpeechToText\\Events\\TranscriptionSuccessfulEvent' => __DIR__ . '/../../..' . '/lib/public/SpeechToText/Events/TranscriptionSuccessfulEvent.php',
|
||||
|
|
@ -2185,10 +2187,10 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
|
|||
'OC\\Share\\Helper' => __DIR__ . '/../../..' . '/lib/private/Share/Helper.php',
|
||||
'OC\\Share\\Share' => __DIR__ . '/../../..' . '/lib/private/Share/Share.php',
|
||||
'OC\\Snowflake\\APCuSequence' => __DIR__ . '/../../..' . '/lib/private/Snowflake/APCuSequence.php',
|
||||
'OC\\Snowflake\\Decoder' => __DIR__ . '/../../..' . '/lib/private/Snowflake/Decoder.php',
|
||||
'OC\\Snowflake\\FileSequence' => __DIR__ . '/../../..' . '/lib/private/Snowflake/FileSequence.php',
|
||||
'OC\\Snowflake\\Generator' => __DIR__ . '/../../..' . '/lib/private/Snowflake/Generator.php',
|
||||
'OC\\Snowflake\\ISequence' => __DIR__ . '/../../..' . '/lib/private/Snowflake/ISequence.php',
|
||||
'OC\\Snowflake\\SnowflakeDecoder' => __DIR__ . '/../../..' . '/lib/private/Snowflake/SnowflakeDecoder.php',
|
||||
'OC\\Snowflake\\SnowflakeGenerator' => __DIR__ . '/../../..' . '/lib/private/Snowflake/SnowflakeGenerator.php',
|
||||
'OC\\SpeechToText\\SpeechToTextManager' => __DIR__ . '/../../..' . '/lib/private/SpeechToText/SpeechToTextManager.php',
|
||||
'OC\\SpeechToText\\TranscriptionJob' => __DIR__ . '/../../..' . '/lib/private/SpeechToText/TranscriptionJob.php',
|
||||
'OC\\StreamImage' => __DIR__ . '/../../..' . '/lib/private/StreamImage.php',
|
||||
|
|
|
|||
|
|
@ -102,6 +102,7 @@ class PublicKeyToken extends Entity implements INamedToken, IWipeableToken {
|
|||
}
|
||||
|
||||
public function getId(): int {
|
||||
assert(!is_string($this->id) && $this->id !== null);
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use OCP\DB\Exception;
|
|||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\IConfig;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use OCP\Snowflake\ISnowflakeGenerator;
|
||||
use Override;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
|
@ -34,7 +34,7 @@ class JobList implements IJobList {
|
|||
protected readonly IConfig $config,
|
||||
protected readonly ITimeFactory $timeFactory,
|
||||
protected readonly LoggerInterface $logger,
|
||||
protected readonly IGenerator $generator,
|
||||
protected readonly ISnowflakeGenerator $snowflakeGenerator,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ class JobList implements IJobList {
|
|||
if (!$this->has($job, $argument)) {
|
||||
$query->insert('jobs')
|
||||
->values([
|
||||
'id' => $query->createNamedParameter($this->generator->nextId()),
|
||||
'id' => $query->createNamedParameter($this->snowflakeGenerator->nextId()),
|
||||
'class' => $query->createNamedParameter($class),
|
||||
'argument' => $query->createNamedParameter($argumentJson),
|
||||
'argument_hash' => $query->createNamedParameter(hash('sha256', $argumentJson)),
|
||||
|
|
|
|||
|
|
@ -11,14 +11,13 @@ declare(strict_types=1);
|
|||
namespace OC\Preview\Db;
|
||||
|
||||
use OCP\AppFramework\Db\Entity;
|
||||
use OCP\AppFramework\Db\SnowflakeAwareEntity;
|
||||
use OCP\DB\Types;
|
||||
use OCP\Files\IMimeTypeDetector;
|
||||
|
||||
/**
|
||||
* Preview entity mapped to the oc_previews and oc_preview_locations table.
|
||||
*
|
||||
* @method string getId()
|
||||
* @method void setId(string $id)
|
||||
* @method int getFileId() Get the file id of the original file.
|
||||
* @method void setFileId(int $fileId)
|
||||
* @method int getStorageId() Get the storage id of the original file.
|
||||
|
|
@ -55,7 +54,7 @@ use OCP\Files\IMimeTypeDetector;
|
|||
*
|
||||
* @see PreviewMapper
|
||||
*/
|
||||
class Preview extends Entity {
|
||||
class Preview extends SnowflakeAwareEntity {
|
||||
protected ?int $fileId = null;
|
||||
protected ?int $oldFileId = null;
|
||||
protected ?int $storageId = null;
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ use OCP\DB\Exception;
|
|||
use OCP\DB\QueryBuilder\IQueryBuilder;
|
||||
use OCP\Files\IMimeTypeLoader;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use OCP\Snowflake\ISnowflakeGenerator;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
|
|
@ -30,7 +30,7 @@ class PreviewMapper extends QBMapper {
|
|||
public function __construct(
|
||||
IDBConnection $db,
|
||||
private readonly IMimeTypeLoader $mimeTypeLoader,
|
||||
private readonly IGenerator $snowflake,
|
||||
private readonly ISnowflakeGenerator $snowflake,
|
||||
) {
|
||||
parent::__construct($db, self::TABLE_NAME, Preview::class);
|
||||
}
|
||||
|
|
@ -52,15 +52,14 @@ class PreviewMapper extends QBMapper {
|
|||
|
||||
if ($preview->getVersion() !== null && $preview->getVersion() !== '') {
|
||||
$qb = $this->db->getQueryBuilder();
|
||||
$id = $this->snowflake->nextId();
|
||||
$qb->insert(self::VERSION_TABLE_NAME)
|
||||
->values([
|
||||
'id' => $qb->createNamedParameter($id),
|
||||
'id' => $qb->createNamedParameter($preview->getId()),
|
||||
'version' => $qb->createNamedParameter($preview->getVersion(), IQueryBuilder::PARAM_STR),
|
||||
'file_id' => $qb->createNamedParameter($preview->getFileId()),
|
||||
])
|
||||
->executeStatement();
|
||||
$entity->setVersionId($id);
|
||||
$entity->setVersionId((string)$preview->getId());
|
||||
}
|
||||
return parent::insert($preview);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ use OCP\IPreview;
|
|||
use OCP\IStreamImage;
|
||||
use OCP\Preview\BeforePreviewFetchedEvent;
|
||||
use OCP\Preview\IVersionedPreviewFile;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class Generator {
|
||||
|
|
@ -38,7 +37,6 @@ class Generator {
|
|||
private LoggerInterface $logger,
|
||||
private PreviewMapper $previewMapper,
|
||||
private StorageFactory $storageFactory,
|
||||
private IGenerator $snowflakeGenerator,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -350,7 +348,7 @@ class Generator {
|
|||
|
||||
try {
|
||||
$previewEntry = new Preview();
|
||||
$previewEntry->setId($this->snowflakeGenerator->nextId());
|
||||
$previewEntry->generateId();
|
||||
$previewEntry->setFileId($file->getId());
|
||||
$previewEntry->setStorageId($file->getMountPoint()->getNumericStorageId());
|
||||
$previewEntry->setSourceMimeType($file->getMimeType());
|
||||
|
|
@ -504,7 +502,7 @@ class Generator {
|
|||
}
|
||||
|
||||
$previewEntry = new Preview();
|
||||
$previewEntry->setId($this->snowflakeGenerator->nextId());
|
||||
$previewEntry->generateId();
|
||||
$previewEntry->setFileId($file->getId());
|
||||
$previewEntry->setStorageId($file->getMountPoint()->getNumericStorageId());
|
||||
$previewEntry->setWidth($width);
|
||||
|
|
@ -545,7 +543,7 @@ class Generator {
|
|||
throw new \RuntimeException('Unable to write preview file');
|
||||
}
|
||||
$previewEntry->setSize($size);
|
||||
|
||||
$previewEntry->generateId();
|
||||
return $this->previewMapper->insert($previewEntry);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ use OCP\Files\NotPermittedException;
|
|||
use OCP\IAppConfig;
|
||||
use OCP\IConfig;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use OCP\Snowflake\ISnowflakeGenerator;
|
||||
use Override;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use RecursiveDirectoryIterator;
|
||||
|
|
@ -39,7 +39,7 @@ class LocalPreviewStorage implements IPreviewStorage {
|
|||
private readonly IDBConnection $connection,
|
||||
private readonly IMimeTypeDetector $mimeTypeDetector,
|
||||
private readonly LoggerInterface $logger,
|
||||
private readonly IGenerator $generator,
|
||||
private readonly ISnowflakeGenerator $generator,
|
||||
) {
|
||||
$this->instanceId = $this->config->getSystemValueString('instanceid');
|
||||
$this->rootFolder = $this->config->getSystemValue('datadirectory', OC::$SERVERROOT . '/data');
|
||||
|
|
@ -120,7 +120,7 @@ class LocalPreviewStorage implements IPreviewStorage {
|
|||
$this->logger->error('Unable to parse preview information for ' . $file->getRealPath());
|
||||
continue;
|
||||
}
|
||||
$preview->setId($this->generator->nextId());
|
||||
$preview->generateId();
|
||||
try {
|
||||
$preview->setSize($file->getSize());
|
||||
$preview->setMtime($file->getMtime());
|
||||
|
|
@ -154,7 +154,7 @@ class LocalPreviewStorage implements IPreviewStorage {
|
|||
$preview->setStorageId($result[0]['storage']);
|
||||
$preview->setEtag($result[0]['etag']);
|
||||
$preview->setSourceMimetype($result[0]['mimetype']);
|
||||
|
||||
$preview->generateId();
|
||||
// try to insert, if that fails the preview is already in the DB
|
||||
$this->previewMapper->insert($preview);
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ use OCP\IBinaryFinder;
|
|||
use OCP\IConfig;
|
||||
use OCP\IPreview;
|
||||
use OCP\Preview\IProviderV2;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
|
@ -142,7 +141,6 @@ class PreviewManager implements IPreview {
|
|||
$this->container->get(LoggerInterface::class),
|
||||
$this->container->get(PreviewMapper::class),
|
||||
$this->container->get(StorageFactory::class),
|
||||
$this->container->get(IGenerator::class),
|
||||
);
|
||||
}
|
||||
return $this->generator;
|
||||
|
|
|
|||
|
|
@ -117,10 +117,10 @@ use OC\SetupCheck\SetupCheckManager;
|
|||
use OC\Share20\ProviderFactory;
|
||||
use OC\Share20\ShareHelper;
|
||||
use OC\Snowflake\APCuSequence;
|
||||
use OC\Snowflake\Decoder;
|
||||
use OC\Snowflake\FileSequence;
|
||||
use OC\Snowflake\Generator;
|
||||
use OC\Snowflake\ISequence;
|
||||
use OC\Snowflake\SnowflakeDecoder;
|
||||
use OC\Snowflake\SnowflakeGenerator;
|
||||
use OC\SpeechToText\SpeechToTextManager;
|
||||
use OC\SystemTag\ManagerFactory as SystemTagManagerFactory;
|
||||
use OC\Talk\Broker;
|
||||
|
|
@ -179,6 +179,7 @@ use OCP\IBinaryFinder;
|
|||
use OCP\ICache;
|
||||
use OCP\ICacheFactory;
|
||||
use OCP\ICertificateManager;
|
||||
use OCP\IConfig;
|
||||
use OCP\IDateTimeFormatter;
|
||||
use OCP\IDateTimeZone;
|
||||
use OCP\IDBConnection;
|
||||
|
|
@ -230,8 +231,8 @@ use OCP\Settings\IDeclarativeManager;
|
|||
use OCP\SetupCheck\ISetupCheckManager;
|
||||
use OCP\Share\IProviderFactory;
|
||||
use OCP\Share\IShareHelper;
|
||||
use OCP\Snowflake\IDecoder;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use OCP\Snowflake\ISnowflakeDecoder;
|
||||
use OCP\Snowflake\ISnowflakeGenerator;
|
||||
use OCP\SpeechToText\ISpeechToTextManager;
|
||||
use OCP\SystemTag\ISystemTagManager;
|
||||
use OCP\SystemTag\ISystemTagObjectMapper;
|
||||
|
|
@ -1266,7 +1267,7 @@ class Server extends ServerContainer implements IServerContainer {
|
|||
|
||||
$this->registerAlias(ISignatureManager::class, SignatureManager::class);
|
||||
|
||||
$this->registerAlias(IGenerator::class, Generator::class);
|
||||
$this->registerAlias(ISnowflakeGenerator::class, SnowflakeGenerator::class);
|
||||
$this->registerService(ISequence::class, function (ContainerInterface $c): ISequence {
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
$sequence = $c->get(APCuSequence::class);
|
||||
|
|
@ -1277,7 +1278,7 @@ class Server extends ServerContainer implements IServerContainer {
|
|||
|
||||
return $c->get(FileSequence::class);
|
||||
}, false);
|
||||
$this->registerAlias(IDecoder::class, Decoder::class);
|
||||
$this->registerAlias(ISnowflakeDecoder::class, SnowflakeDecoder::class);
|
||||
|
||||
$this->connectDispatcher();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ class AuthorizedGroup extends Entity implements \JsonSerializable {
|
|||
|
||||
public function jsonSerialize(): array {
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'id' => $this->getId(),
|
||||
'group_id' => $this->groupId,
|
||||
'class' => $this->class
|
||||
];
|
||||
|
|
|
|||
|
|
@ -26,11 +26,7 @@ class APCuSequence implements ISequence {
|
|||
}
|
||||
|
||||
$key = 'seq:' . $seconds . ':' . $milliseconds;
|
||||
$sequenceId = apcu_inc($key, success: $success, ttl: 1);
|
||||
if ($success === true) {
|
||||
return $sequenceId;
|
||||
}
|
||||
|
||||
throw new \Exception('Failed to generate SnowflakeId with APCu');
|
||||
$sequenceId = apcu_inc($key, ttl: 1);
|
||||
return $sequenceId === false ? throw new \Exception('Failed to generate SnowflakeId with APCu') : $sequenceId;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,8 +9,9 @@ declare(strict_types=1);
|
|||
|
||||
namespace OC\Snowflake;
|
||||
|
||||
use OCP\Snowflake\IDecoder;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use OCP\Snowflake\ISnowflakeDecoder;
|
||||
use OCP\Snowflake\ISnowflakeGenerator;
|
||||
use OCP\Snowflake\Snowflake;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
|
|
@ -20,9 +21,9 @@ use Override;
|
|||
*
|
||||
* @since 33.0.0
|
||||
*/
|
||||
final class Decoder implements IDecoder {
|
||||
final class SnowflakeDecoder implements ISnowflakeDecoder {
|
||||
#[Override]
|
||||
public function decode(string $snowflakeId): array {
|
||||
public function decode(string $snowflakeId): Snowflake {
|
||||
if (!ctype_digit($snowflakeId)) {
|
||||
throw new \Exception('Invalid Snowflake ID: ' . $snowflakeId);
|
||||
}
|
||||
|
|
@ -35,12 +36,19 @@ final class Decoder implements IDecoder {
|
|||
$data['createdAt'] = new \DateTimeImmutable(
|
||||
sprintf(
|
||||
'@%d.%03d',
|
||||
$data['seconds'] + IGenerator::TS_OFFSET + intdiv($data['milliseconds'], 1000),
|
||||
$data['seconds'] + ISnowflakeGenerator::TS_OFFSET + intdiv($data['milliseconds'], 1000),
|
||||
$data['milliseconds'] % 1000,
|
||||
)
|
||||
);
|
||||
|
||||
return $data;
|
||||
return new Snowflake(
|
||||
$data['serverId'],
|
||||
$data['sequenceId'],
|
||||
$data['isCli'],
|
||||
$data['seconds'],
|
||||
$data['milliseconds'],
|
||||
$data['createdAt'],
|
||||
);
|
||||
}
|
||||
|
||||
private function decode64bits(int $snowflakeId): array {
|
||||
|
|
@ -51,11 +59,11 @@ final class Decoder implements IDecoder {
|
|||
$milliseconds = $secondHalf >> 22;
|
||||
|
||||
return [
|
||||
'seconds' => $seconds,
|
||||
'milliseconds' => $milliseconds,
|
||||
'serverId' => ($secondHalf >> 13) & 0x1FF,
|
||||
'sequenceId' => $secondHalf & 0xFFF,
|
||||
'isCli' => (bool)(($secondHalf >> 12) & 0x1),
|
||||
'seconds' => $seconds,
|
||||
'milliseconds' => $milliseconds,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -88,12 +96,12 @@ final class Decoder implements IDecoder {
|
|||
$hex = '';
|
||||
$digits = '0123456789ABCDEF';
|
||||
|
||||
while (strlen($decimal) > 0 && $decimal !== '0') {
|
||||
while ($decimal !== '' && $decimal !== '0') {
|
||||
$remainder = 0;
|
||||
$newDecimal = '';
|
||||
|
||||
// Perform division by 16 manually for arbitrary precision
|
||||
for ($i = 0; $i < strlen($decimal); $i++) {
|
||||
for ($i = 0, $iMax = strlen($decimal); $i < $iMax; $i++) {
|
||||
$digit = (int)$decimal[$i];
|
||||
$current = $remainder * 10 + $digit;
|
||||
|
||||
|
|
@ -104,7 +112,7 @@ final class Decoder implements IDecoder {
|
|||
} else {
|
||||
$remainder = $current;
|
||||
// Only add quotient digit if we already have some digits in result
|
||||
if (strlen($newDecimal) > 0) {
|
||||
if ($newDecimal !== '') {
|
||||
$newDecimal .= '0';
|
||||
}
|
||||
}
|
||||
|
|
@ -11,7 +11,7 @@ namespace OC\Snowflake;
|
|||
|
||||
use OCP\AppFramework\Utility\ITimeFactory;
|
||||
use OCP\IConfig;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use OCP\Snowflake\ISnowflakeGenerator;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
|
|
@ -21,11 +21,11 @@ use Override;
|
|||
*
|
||||
* @since 33.0.0
|
||||
*/
|
||||
final class Generator implements IGenerator {
|
||||
final readonly class SnowflakeGenerator implements ISnowflakeGenerator {
|
||||
public function __construct(
|
||||
private readonly ITimeFactory $timeFactory,
|
||||
private readonly IConfig $config,
|
||||
private readonly ISequence $sequenceGenerator,
|
||||
private ITimeFactory $timeFactory,
|
||||
private IConfig $config,
|
||||
private ISequence $sequenceGenerator,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -290,7 +290,7 @@ class Tags implements ITags {
|
|||
return false;
|
||||
}
|
||||
$this->logger->debug(__METHOD__ . ' Added an tag with ' . $tag->getId(), ['app' => 'core']);
|
||||
return $tag->getId();
|
||||
return $tag->getId() ?? false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -19,11 +19,9 @@ use function substr;
|
|||
* @psalm-consistent-constructor
|
||||
*/
|
||||
abstract class Entity {
|
||||
/** @var int $id */
|
||||
public $id = null;
|
||||
|
||||
public int|string|null $id = null;
|
||||
private array $_updatedFields = [];
|
||||
/** @var array<string, \OCP\DB\Types::*> */
|
||||
/** @psalm-param $_fieldTypes array<string, Types::*> */
|
||||
private array $_fieldTypes = ['id' => 'integer'];
|
||||
|
||||
/**
|
||||
|
|
@ -43,7 +41,6 @@ abstract class Entity {
|
|||
return $instance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Maps the keys of the row array to the attributes
|
||||
* @param array $row the row to map onto the entity
|
||||
|
|
@ -64,7 +61,7 @@ abstract class Entity {
|
|||
|
||||
|
||||
/**
|
||||
* @return array<string, \OCP\DB\Types::*> with attribute and type
|
||||
* @return array<string, Types::*> with attribute and type
|
||||
* @since 7.0.0
|
||||
*/
|
||||
public function getFieldTypes(): array {
|
||||
|
|
@ -266,8 +263,8 @@ abstract class Entity {
|
|||
* that value once its being returned from the database
|
||||
*
|
||||
* @param string $fieldName the name of the attribute
|
||||
* @param \OCP\DB\Types::* $type the type which will be used to match a cast
|
||||
* @since 31.0.0 Parameter $type is now restricted to {@see \OCP\DB\Types} constants. The formerly accidentally supported types 'int'|'bool'|'double' are mapped to Types::INTEGER|Types::BOOLEAN|Types::FLOAT accordingly.
|
||||
* @param Types::* $type the type which will be used to match a cast
|
||||
* @since 31.0.0 Parameter $type is now restricted to {@see Types} constants. The formerly accidentally supported types 'int'|'bool'|'double' are mapped to Types::INTEGER|Types::BOOLEAN|Types::FLOAT accordingly.
|
||||
* @since 7.0.0
|
||||
*/
|
||||
protected function addType(string $fieldName, string $type): void {
|
||||
|
|
|
|||
|
|
@ -108,17 +108,24 @@ abstract class QBMapper {
|
|||
$getter = 'get' . ucfirst($property);
|
||||
$value = $entity->$getter();
|
||||
|
||||
if ($property === 'id' && $entity->id === null) {
|
||||
continue;
|
||||
}
|
||||
$type = $this->getParameterTypeForProperty($entity, $property);
|
||||
$qb->setValue($column, $qb->createNamedParameter($value, $type));
|
||||
}
|
||||
|
||||
$qb->executeStatement();
|
||||
|
||||
if ($entity->id === null) {
|
||||
if ($entity instanceof SnowflakeAwareEntity) {
|
||||
/** @psalm-suppress DocblockTypeContradiction */
|
||||
$entity->generateId();
|
||||
$qb->executeStatement();
|
||||
} elseif ($entity->id === null) {
|
||||
$qb->executeStatement();
|
||||
// When autoincrement is used id is always an int
|
||||
$entity->setId($qb->getLastInsertId());
|
||||
} else {
|
||||
$qb->executeStatement();
|
||||
}
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
|
|
|
|||
58
lib/public/AppFramework/Db/SnowflakeAwareEntity.php
Normal file
58
lib/public/AppFramework/Db/SnowflakeAwareEntity.php
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCP\AppFramework\Db;
|
||||
|
||||
use OCP\AppFramework\Attribute\Consumable;
|
||||
use OCP\DB\Types;
|
||||
use OCP\Server;
|
||||
use OCP\Snowflake\ISnowflakeDecoder;
|
||||
use OCP\Snowflake\ISnowflakeGenerator;
|
||||
use OCP\Snowflake\Snowflake;
|
||||
|
||||
/**
|
||||
* Entity with snowflake support
|
||||
* @method string getId()
|
||||
* @since 33.0.0
|
||||
*/
|
||||
#[Consumable(since: '33.0.0')]
|
||||
abstract class SnowflakeAwareEntity extends Entity {
|
||||
protected ?Snowflake $snowflake = null;
|
||||
|
||||
/** @psalm-param $_fieldTypes array<string, Types::*> */
|
||||
private array $_fieldTypes = ['id' => Types::STRING];
|
||||
|
||||
public function setId($id): void {
|
||||
throw new \LogicException('Use generated id to set a new id to the Snowflake aware entity.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically creates a snowflake ID
|
||||
*/
|
||||
public function generateId(): void {
|
||||
if ($this->id === null) {
|
||||
$this->id = Server::get(ISnowflakeGenerator::class)->nextId();
|
||||
$this->markFieldUpdated('id');
|
||||
}
|
||||
}
|
||||
|
||||
public function getCreatedAt(): ?\DateTimeImmutable {
|
||||
return $this->getSnowflake()?->getCreatedAt();
|
||||
}
|
||||
|
||||
public function getSnowflake(): ?Snowflake {
|
||||
if ($this->id === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->snowflake === null) {
|
||||
$this->snowflake = Server::get(ISnowflakeDecoder::class)->decode($this->id);
|
||||
}
|
||||
|
||||
return $this->snowflake;
|
||||
}
|
||||
}
|
||||
|
|
@ -14,11 +14,11 @@ use OCP\AppFramework\Attribute\Consumable;
|
|||
/**
|
||||
* Nextcloud Snowflake ID decoder
|
||||
*
|
||||
* @see \OCP\Snowflake\IGenerator for format
|
||||
* @see \OCP\Snowflake\ISnowflakeGenerator for format
|
||||
* @since 33.0.0
|
||||
*/
|
||||
#[Consumable(since: '33.0.0')]
|
||||
interface IDecoder {
|
||||
interface ISnowflakeDecoder {
|
||||
/**
|
||||
* Decode information contained into Snowflake ID
|
||||
*
|
||||
|
|
@ -28,8 +28,8 @@ interface IDecoder {
|
|||
* - createdAt: timestamp at which ID was generated
|
||||
* - isCli: if ID was generated using CLI or not
|
||||
*
|
||||
* @return array{createdAt: \DateTimeImmutable, serverId: int<0,1023>, sequenceId: int<0,4095>, isCli: bool, seconds: positive-int, milliseconds: int<0,999>}
|
||||
* @return Snowflake
|
||||
* @since 33.0
|
||||
*/
|
||||
public function decode(string $snowflakeId): array;
|
||||
public function decode(string $snowflakeId): Snowflake;
|
||||
}
|
||||
|
|
@ -25,7 +25,7 @@ use OCP\AppFramework\Attribute\Consumable;
|
|||
* @since 33.0.0
|
||||
*/
|
||||
#[Consumable(since: '33.0.0')]
|
||||
interface IGenerator {
|
||||
interface ISnowflakeGenerator {
|
||||
|
||||
/**
|
||||
* Offset applied on timestamps to keep it short
|
||||
72
lib/public/Snowflake/Snowflake.php
Normal file
72
lib/public/Snowflake/Snowflake.php
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCP\Snowflake;
|
||||
|
||||
use OCP\AppFramework\Attribute\Consumable;
|
||||
|
||||
/**
|
||||
* Nextcloud Snowflake DTO
|
||||
*
|
||||
* @since 33.0.0
|
||||
*/
|
||||
#[Consumable(since: '33.0.0')]
|
||||
final readonly class Snowflake {
|
||||
/**
|
||||
* @psalm-param int<0,1023> $serverId
|
||||
* @psalm-param int<0,4095> $sequenceId
|
||||
* @psalm-param non-negative-int $seconds
|
||||
* @psalm-param int<0,999> $milliseconds
|
||||
*/
|
||||
public function __construct(
|
||||
private int $serverId,
|
||||
private int $sequenceId,
|
||||
private bool $isCli,
|
||||
private int $seconds,
|
||||
private int $milliseconds,
|
||||
private \DateTimeImmutable $createdAt,
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return int<0,1023>
|
||||
*/
|
||||
public function getServerId(): int {
|
||||
return $this->serverId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return int<0,4095>
|
||||
*/
|
||||
public function getSequenceId(): int {
|
||||
return $this->sequenceId;
|
||||
}
|
||||
|
||||
public function isCli(): bool {
|
||||
return $this->isCli;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return non-negative-int
|
||||
*/
|
||||
public function getSeconds(): int {
|
||||
return $this->seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return int<0,999>
|
||||
*/
|
||||
public function getMilliseconds(): int {
|
||||
return $this->milliseconds;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): \DateTimeImmutable {
|
||||
return $this->createdAt;
|
||||
}
|
||||
}
|
||||
|
|
@ -13,7 +13,7 @@ use OC\BackgroundJob\JobList;
|
|||
use OCP\BackgroundJob\IJob;
|
||||
use OCP\BackgroundJob\Job;
|
||||
use OCP\Server;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use OCP\Snowflake\ISnowflakeGenerator;
|
||||
|
||||
/**
|
||||
* Class DummyJobList
|
||||
|
|
@ -46,7 +46,7 @@ class DummyJobList extends JobList {
|
|||
$job = Server::get($job);
|
||||
}
|
||||
$job->setArgument($argument);
|
||||
$job->setId(Server::get(IGenerator::class)->nextId());
|
||||
$job->setId(Server::get(ISnowflakeGenerator::class)->nextId());
|
||||
if (!$this->has($job, null)) {
|
||||
$this->jobs[] = $job;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-FileCopyrightText: 2016-2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-FileCopyrightText: 2016 ownCloud, Inc.
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
|
@ -16,7 +16,7 @@ use OCP\DB\QueryBuilder\IQueryBuilder;
|
|||
use OCP\IConfig;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Server;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use OCP\Snowflake\ISnowflakeGenerator;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
|
@ -46,7 +46,7 @@ class JobListTest extends TestCase {
|
|||
$this->config,
|
||||
$this->timeFactory,
|
||||
Server::get(LoggerInterface::class),
|
||||
Server::get(IGenerator::class),
|
||||
Server::get(ISnowflakeGenerator::class),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -146,7 +146,7 @@ class JobListTest extends TestCase {
|
|||
if ($lastChecked === 0) {
|
||||
$lastChecked = time();
|
||||
}
|
||||
$id = Server::get(IGenerator::class)->nextId();
|
||||
$id = Server::get(ISnowflakeGenerator::class)->nextId();
|
||||
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->insert('jobs')
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ use OCP\IPreview;
|
|||
use OCP\Preview\BeforePreviewFetchedEvent;
|
||||
use OCP\Preview\IProviderV2;
|
||||
use OCP\Preview\IVersionedPreviewFile;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\Attributes\TestWith;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
|
@ -42,7 +41,6 @@ class GeneratorTest extends TestCase {
|
|||
private LoggerInterface&MockObject $logger;
|
||||
private StorageFactory&MockObject $storageFactory;
|
||||
private PreviewMapper&MockObject $previewMapper;
|
||||
private IGenerator&MockObject $snowflakeGenerator;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
|
@ -54,7 +52,6 @@ class GeneratorTest extends TestCase {
|
|||
$this->logger = $this->createMock(LoggerInterface::class);
|
||||
$this->previewMapper = $this->createMock(PreviewMapper::class);
|
||||
$this->storageFactory = $this->createMock(StorageFactory::class);
|
||||
$this->snowflakeGenerator = $this->createMock(IGenerator::class);
|
||||
|
||||
$this->generator = new Generator(
|
||||
$this->config,
|
||||
|
|
@ -64,7 +61,6 @@ class GeneratorTest extends TestCase {
|
|||
$this->logger,
|
||||
$this->previewMapper,
|
||||
$this->storageFactory,
|
||||
$this->snowflakeGenerator,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ use OCP\IAppConfig;
|
|||
use OCP\IConfig;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Server;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use PHPUnit\Framework\Attributes\TestDox;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
|
@ -124,7 +123,6 @@ class MovePreviewJobTest extends TestCase {
|
|||
$this->mimeTypeDetector,
|
||||
$this->mimeTypeLoader,
|
||||
$this->logger,
|
||||
Server::get(IGenerator::class),
|
||||
Server::get(IAppDataFactory::class),
|
||||
);
|
||||
$this->invokePrivate($job, 'run', [[]]);
|
||||
|
|
@ -157,7 +155,6 @@ class MovePreviewJobTest extends TestCase {
|
|||
$this->mimeTypeDetector,
|
||||
$this->mimeTypeLoader,
|
||||
$this->logger,
|
||||
Server::get(IGenerator::class),
|
||||
Server::get(IAppDataFactory::class)
|
||||
);
|
||||
$this->invokePrivate($job, 'run', [[]]);
|
||||
|
|
@ -198,7 +195,6 @@ class MovePreviewJobTest extends TestCase {
|
|||
$this->mimeTypeDetector,
|
||||
$this->mimeTypeLoader,
|
||||
$this->logger,
|
||||
Server::get(IGenerator::class),
|
||||
Server::get(IAppDataFactory::class)
|
||||
);
|
||||
$this->invokePrivate($job, 'run', [[]]);
|
||||
|
|
|
|||
|
|
@ -14,20 +14,20 @@ use OC\Preview\Db\Preview;
|
|||
use OC\Preview\Db\PreviewMapper;
|
||||
use OCP\IDBConnection;
|
||||
use OCP\Server;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use OCP\Snowflake\ISnowflakeGenerator;
|
||||
use Test\TestCase;
|
||||
|
||||
#[\PHPUnit\Framework\Attributes\Group('DB')]
|
||||
class PreviewMapperTest extends TestCase {
|
||||
private PreviewMapper $previewMapper;
|
||||
private IDBConnection $connection;
|
||||
private IGenerator $snowflake;
|
||||
private ISnowflakeGenerator $snowflake;
|
||||
|
||||
public function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->previewMapper = Server::get(PreviewMapper::class);
|
||||
$this->connection = Server::get(IDBConnection::class);
|
||||
$this->snowflake = Server::get(IGenerator::class);
|
||||
$this->snowflake = Server::get(ISnowflakeGenerator::class);
|
||||
|
||||
$qb = $this->connection->getQueryBuilder();
|
||||
$qb->delete('preview_locations')->executeStatement();
|
||||
|
|
@ -79,7 +79,7 @@ class PreviewMapperTest extends TestCase {
|
|||
$qb->executeStatement();
|
||||
}
|
||||
$preview = new Preview();
|
||||
$preview->setId($this->snowflake->nextId());
|
||||
$preview->generateId();
|
||||
$preview->setFileId($fileId);
|
||||
$preview->setStorageId(1);
|
||||
$preview->setCropped(true);
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ use OC\Preview\Db\Preview;
|
|||
use OC\Preview\Db\PreviewMapper;
|
||||
use OC\Preview\PreviewService;
|
||||
use OCP\Server;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
#[CoversClass(PreviewService::class)]
|
||||
|
|
@ -22,13 +21,11 @@ use PHPUnit\Framework\TestCase;
|
|||
class PreviewServiceTest extends TestCase {
|
||||
private PreviewService $previewService;
|
||||
private PreviewMapper $previewMapper;
|
||||
private IGenerator $snowflakeGenerator;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
$this->previewService = Server::get(PreviewService::class);
|
||||
$this->previewMapper = Server::get(PreviewMapper::class);
|
||||
$this->snowflakeGenerator = Server::get(IGenerator::class);
|
||||
$this->previewService->deleteAll();
|
||||
}
|
||||
|
||||
|
|
@ -40,7 +37,7 @@ class PreviewServiceTest extends TestCase {
|
|||
public function testGetAvailableFileIds(): void {
|
||||
foreach (range(1, 20) as $i) {
|
||||
$preview = new Preview();
|
||||
$preview->setId($this->snowflakeGenerator->nextId());
|
||||
$preview->generateId();
|
||||
$preview->setFileId($i % 10);
|
||||
$preview->setStorageId(1);
|
||||
$preview->setWidth($i);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
namespace Test\Snowflake;
|
||||
|
||||
use OC\Snowflake\Decoder;
|
||||
use OC\Snowflake\SnowflakeDecoder;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use Test\TestCase;
|
||||
|
||||
|
|
@ -15,10 +15,10 @@ use Test\TestCase;
|
|||
* @package Test
|
||||
*/
|
||||
class DecoderTest extends TestCase {
|
||||
private Decoder $decoder;
|
||||
private SnowflakeDecoder $decoder;
|
||||
|
||||
public function setUp():void {
|
||||
$this->decoder = new Decoder();
|
||||
$this->decoder = new SnowflakeDecoder();
|
||||
}
|
||||
|
||||
#[DataProvider('provideSnowflakeIds')]
|
||||
|
|
@ -31,10 +31,10 @@ class DecoderTest extends TestCase {
|
|||
): void {
|
||||
$data = $this->decoder->decode($snowflakeId);
|
||||
|
||||
$this->assertEquals($timestamp, (float)$data['createdAt']->format('U.v'));
|
||||
$this->assertEquals($serverId, $data['serverId']);
|
||||
$this->assertEquals($sequenceId, $data['sequenceId']);
|
||||
$this->assertEquals($isCli, $data['isCli']);
|
||||
$this->assertEquals($timestamp, (float)$data->getCreatedAt()->format('U.v'));
|
||||
$this->assertEquals($serverId, $data->getServerId());
|
||||
$this->assertEquals($sequenceId, $data->getSequenceId());
|
||||
$this->assertEquals($isCli, $data->isCli());
|
||||
}
|
||||
|
||||
public static function provideSnowflakeIds(): array {
|
||||
|
|
|
|||
|
|
@ -10,12 +10,12 @@ declare(strict_types=1);
|
|||
namespace Test\Snowflake;
|
||||
|
||||
use OC\AppFramework\Utility\TimeFactory;
|
||||
use OC\Snowflake\Decoder;
|
||||
use OC\Snowflake\Generator;
|
||||
use OC\Snowflake\ISequence;
|
||||
use OC\Snowflake\SnowflakeDecoder;
|
||||
use OC\Snowflake\SnowflakeGenerator;
|
||||
use OCP\AppFramework\Utility\ITimeFactory;
|
||||
use OCP\IConfig;
|
||||
use OCP\Snowflake\IGenerator;
|
||||
use OCP\Snowflake\ISnowflakeGenerator;
|
||||
use PHPUnit\Framework\Attributes\DataProvider;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Test\TestCase;
|
||||
|
|
@ -24,12 +24,12 @@ use Test\TestCase;
|
|||
* @package Test
|
||||
*/
|
||||
class GeneratorTest extends TestCase {
|
||||
private Decoder $decoder;
|
||||
private SnowflakeDecoder $decoder;
|
||||
private IConfig&MockObject $config;
|
||||
private ISequence&MockObject $sequence;
|
||||
|
||||
public function setUp():void {
|
||||
$this->decoder = new Decoder();
|
||||
$this->decoder = new SnowflakeDecoder();
|
||||
|
||||
$this->config = $this->createMock(IConfig::class);
|
||||
$this->config->method('getSystemValueInt')
|
||||
|
|
@ -43,27 +43,27 @@ class GeneratorTest extends TestCase {
|
|||
}
|
||||
|
||||
public function testGenerator(): void {
|
||||
$generator = new Generator(new TimeFactory(), $this->config, $this->sequence);
|
||||
$generator = new SnowflakeGenerator(new TimeFactory(), $this->config, $this->sequence);
|
||||
$snowflakeId = $generator->nextId();
|
||||
$data = $this->decoder->decode($generator->nextId());
|
||||
|
||||
$this->assertIsString($snowflakeId);
|
||||
// Check timestamp
|
||||
$this->assertGreaterThan(time() - 30, $data['createdAt']->format('U'));
|
||||
$this->assertGreaterThan(time() - 30, $data->getCreatedAt()->format('U'));
|
||||
|
||||
// Check serverId
|
||||
$this->assertGreaterThanOrEqual(0, $data['serverId']);
|
||||
$this->assertLessThanOrEqual(1023, $data['serverId']);
|
||||
$this->assertGreaterThanOrEqual(0, $data->getServerId());
|
||||
$this->assertLessThanOrEqual(1023, $data->getServerId());
|
||||
|
||||
// Check sequenceId
|
||||
$this->assertGreaterThanOrEqual(0, $data['sequenceId']);
|
||||
$this->assertLessThanOrEqual(4095, $data['sequenceId']);
|
||||
$this->assertGreaterThanOrEqual(0, $data->getSequenceId());
|
||||
$this->assertLessThanOrEqual(4095, $data->getSequenceId());
|
||||
|
||||
// Check CLI
|
||||
$this->assertTrue($data['isCli']);
|
||||
$this->assertTrue($data->isCli());
|
||||
|
||||
// Check serverId
|
||||
$this->assertEquals(42, $data['serverId']);
|
||||
$this->assertEquals(42, $data->getServerId());
|
||||
}
|
||||
|
||||
#[DataProvider('provideSnowflakeData')]
|
||||
|
|
@ -72,12 +72,12 @@ class GeneratorTest extends TestCase {
|
|||
$timeFactory = $this->createMock(ITimeFactory::class);
|
||||
$timeFactory->method('now')->willReturn($dt);
|
||||
|
||||
$generator = new Generator($timeFactory, $this->config, $this->sequence);
|
||||
$generator = new SnowflakeGenerator($timeFactory, $this->config, $this->sequence);
|
||||
$data = $this->decoder->decode($generator->nextId());
|
||||
|
||||
$this->assertEquals($expectedSeconds, ($data['createdAt']->format('U') - IGenerator::TS_OFFSET));
|
||||
$this->assertEquals($expectedMilliseconds, (int)$data['createdAt']->format('v'));
|
||||
$this->assertEquals(42, $data['serverId']);
|
||||
$this->assertEquals($expectedSeconds, ($data->getCreatedAt()->format('U') - ISnowflakeGenerator::TS_OFFSET));
|
||||
$this->assertEquals($expectedMilliseconds, (int)$data->getCreatedAt()->format('v'));
|
||||
$this->assertEquals(42, $data->getServerId());
|
||||
}
|
||||
|
||||
public static function provideSnowflakeData(): array {
|
||||
|
|
|
|||
Loading…
Reference in a new issue