AppData.php 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2016 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-License-Identifier: AGPL-3.0-or-later
  6. */
  7. namespace OC\Files\AppData;
  8. use OC\Files\SimpleFS\SimpleFolder;
  9. use OC\SystemConfig;
  10. use OCP\Cache\CappedMemoryCache;
  11. use OCP\Files\Folder;
  12. use OCP\Files\IAppData;
  13. use OCP\Files\IRootFolder;
  14. use OCP\Files\Node;
  15. use OCP\Files\NotFoundException;
  16. use OCP\Files\NotPermittedException;
  17. use OCP\Files\SimpleFS\ISimpleFolder;
  18. class AppData implements IAppData {
  19. private IRootFolder $rootFolder;
  20. private SystemConfig $config;
  21. private string $appId;
  22. private ?Folder $folder = null;
  23. /** @var CappedMemoryCache<ISimpleFolder|NotFoundException> */
  24. private CappedMemoryCache $folders;
  25. /**
  26. * AppData constructor.
  27. *
  28. * @param IRootFolder $rootFolder
  29. * @param SystemConfig $systemConfig
  30. * @param string $appId
  31. */
  32. public function __construct(IRootFolder $rootFolder,
  33. SystemConfig $systemConfig,
  34. string $appId) {
  35. $this->rootFolder = $rootFolder;
  36. $this->config = $systemConfig;
  37. $this->appId = $appId;
  38. $this->folders = new CappedMemoryCache();
  39. }
  40. private function getAppDataFolderName() {
  41. $instanceId = $this->config->getValue('instanceid', null);
  42. if ($instanceId === null) {
  43. throw new \RuntimeException('no instance id!');
  44. }
  45. return 'appdata_' . $instanceId;
  46. }
  47. protected function getAppDataRootFolder(): Folder {
  48. $name = $this->getAppDataFolderName();
  49. try {
  50. /** @var Folder $node */
  51. $node = $this->rootFolder->get($name);
  52. return $node;
  53. } catch (NotFoundException $e) {
  54. try {
  55. return $this->rootFolder->newFolder($name);
  56. } catch (NotPermittedException $e) {
  57. throw new \RuntimeException('Could not get appdata folder');
  58. }
  59. }
  60. }
  61. /**
  62. * @return Folder
  63. * @throws \RuntimeException
  64. */
  65. private function getAppDataFolder(): Folder {
  66. if ($this->folder === null) {
  67. $name = $this->getAppDataFolderName();
  68. try {
  69. $this->folder = $this->rootFolder->get($name . '/' . $this->appId);
  70. } catch (NotFoundException $e) {
  71. $appDataRootFolder = $this->getAppDataRootFolder();
  72. try {
  73. $this->folder = $appDataRootFolder->get($this->appId);
  74. } catch (NotFoundException $e) {
  75. try {
  76. $this->folder = $appDataRootFolder->newFolder($this->appId);
  77. } catch (NotPermittedException $e) {
  78. throw new \RuntimeException('Could not get appdata folder for ' . $this->appId);
  79. }
  80. }
  81. }
  82. }
  83. return $this->folder;
  84. }
  85. public function getFolder(string $name): ISimpleFolder {
  86. $key = $this->appId . '/' . $name;
  87. if ($cachedFolder = $this->folders->get($key)) {
  88. if ($cachedFolder instanceof \Exception) {
  89. throw $cachedFolder;
  90. } else {
  91. return $cachedFolder;
  92. }
  93. }
  94. try {
  95. // Hardening if somebody wants to retrieve '/'
  96. if ($name === '/') {
  97. $node = $this->getAppDataFolder();
  98. } else {
  99. $path = $this->getAppDataFolderName() . '/' . $this->appId . '/' . $name;
  100. $node = $this->rootFolder->get($path);
  101. }
  102. } catch (NotFoundException $e) {
  103. $this->folders->set($key, $e);
  104. throw $e;
  105. }
  106. /** @var Folder $node */
  107. $folder = new SimpleFolder($node);
  108. $this->folders->set($key, $folder);
  109. return $folder;
  110. }
  111. public function newFolder(string $name): ISimpleFolder {
  112. $key = $this->appId . '/' . $name;
  113. $folder = $this->getAppDataFolder()->newFolder($name);
  114. $simpleFolder = new SimpleFolder($folder);
  115. $this->folders->set($key, $simpleFolder);
  116. return $simpleFolder;
  117. }
  118. public function getDirectoryListing(): array {
  119. $listing = $this->getAppDataFolder()->getDirectoryListing();
  120. $fileListing = array_map(function (Node $folder) {
  121. if ($folder instanceof Folder) {
  122. return new SimpleFolder($folder);
  123. }
  124. return null;
  125. }, $listing);
  126. $fileListing = array_filter($fileListing);
  127. return array_values($fileListing);
  128. }
  129. public function getId(): int {
  130. return $this->getAppDataFolder()->getId();
  131. }
  132. }